Add native NPC visitors with contracts, Clover slots, Pyramid, and party table scenes
Implement 32x32 BFS visitor navigation and daily contracts system with companion .npc journals; add native assembly scenes for Clover slots, Pyramid cards, Blackjack Party and Russian Party; package animation and sprite packs; add comprehensive offline test suites and rebuild shipping binaries.
BIN
assets/animations/clover/cabinet-v1.bin
Normal file
20
assets/animations/clover/manifest.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"symbols": [
|
||||
"clover",
|
||||
"lemon",
|
||||
"cherries",
|
||||
"bell",
|
||||
"diamond",
|
||||
"chest",
|
||||
"seven"
|
||||
],
|
||||
"cabinet": [
|
||||
640,
|
||||
480
|
||||
],
|
||||
"symbol": [
|
||||
56,
|
||||
56
|
||||
],
|
||||
"runtime": "MASM; five reels, three complete rows, legacy additive combos"
|
||||
}
|
||||
BIN
assets/animations/clover/symbols-v1.bin
Normal file
BIN
assets/animations/pyramid/balls-v1.bin
Normal file
BIN
assets/animations/pyramid/table-v1.bin
Normal file
BIN
assets/animations/pyramid/table-v2.bin
Normal file
BIN
assets/animations/roulette/participants-v1.bin
Normal file
BIN
assets/animations/tables/blackjack-guests-v1.bin
Normal file
BIN
assets/animations/tables/blackjack-room-v1.bin
Normal file
|
|
@ -251,5 +251,109 @@
|
|||
"symCherry": "ВИШНЯ",
|
||||
"symClover": "КЛЕВЕР",
|
||||
"symGem": "АЛМАЗ",
|
||||
"symCrown": "КОРОНА"
|
||||
"symCrown": "КОРОНА",
|
||||
"npcName6": "Дмитрий Серов",
|
||||
"npcName7": "Виктор Громов",
|
||||
"npcName8": "Григорий Лис",
|
||||
"npcName9": "Павел Мирный",
|
||||
"npcName10": "Антон Богатый",
|
||||
"npcName11": "Алиса Ветрова",
|
||||
"npcGreeting0": "Проверим твою выдержку?",
|
||||
"npcGreeting1": "Сегодня я играю смело.",
|
||||
"npcGreeting2": "Удача любит терпеливых.",
|
||||
"npcGreeting3": "Давай сыграем без спешки.",
|
||||
"npcGreeting4": "Есть дело с наградой.",
|
||||
"npcGreeting5": "Попробуем свои силы?",
|
||||
"npcQuest0": "Заверши любые 3 раунда",
|
||||
"npcQuest1": "Подбрось монетку 3 раза",
|
||||
"npcQuest2": "Выиграй в монетку",
|
||||
"npcQuest3": "Сыграй 2 раунда в блэкджек",
|
||||
"npcQuest4": "Выиграй в блэкджек",
|
||||
"npcQuest5": "Заверши 2 раздачи покера",
|
||||
"npcQuest6": "Выиграй раздачу покера",
|
||||
"npcQuest7": "Сыграй 3 раунда в рулетку",
|
||||
"npcQuest8": "Выиграй в рулетку",
|
||||
"npcQuest9": "Крути автомат 3 раза",
|
||||
"npcQuest10": "Заверши партию в дурака",
|
||||
"npcQuest11": "Выиграй партию в дурака",
|
||||
"npcTalkPrompt3D": "[E] ПОГОВОРИТЬ",
|
||||
"npcContractTitle3D": "ЧЕЛЛЕНДЖ НА СЕГОДНЯ",
|
||||
"npcProgressText3D": "Прогресс",
|
||||
"npcRewardText3D": "Награда",
|
||||
"npcAcceptText3D": "ВЗЯТЬ",
|
||||
"npcClaimText3D": "НАГРАДА",
|
||||
"npcCloseText3D": "ЗАКРЫТЬ",
|
||||
"npcAvailableText3D": "Можно принять",
|
||||
"npcActiveText3D": "Выполняется",
|
||||
"npcReadyText3D": "Готово! Забери награду",
|
||||
"npcDoneText3D": "Награда уже получена",
|
||||
"npcIoErrorText3D": "Не удалось сохранить задание",
|
||||
"cbPartyName0": "ТОЛЯ",
|
||||
"cbPartyName1": "СЕРГЕЙ",
|
||||
"cbPartyName2": "АЛИСА",
|
||||
"cbBotsLabel3D": "БОТЫ",
|
||||
"cbBotWaitText3D": "ЖДЁТ",
|
||||
"cbBotHitText3D": "КАРТА",
|
||||
"cbBotStandText3D": "ХВАТИТ",
|
||||
"cbBotBustText3D": "ПЕРЕБОР",
|
||||
"cbBotWinText3D": "ПОБЕДА",
|
||||
"cbBotLoseText3D": "ПРОИГРЫШ",
|
||||
"cbBotPushText3D": "НИЧЬЯ",
|
||||
"cbBotNaturalText3D": "БЛЭКДЖЕК",
|
||||
"cbDealerLabel3D": "ДИЛЕР",
|
||||
"cbPartyPlayerText3D": "ВЫ",
|
||||
"rrPartyName0": "ТОЛЯ",
|
||||
"rrPartyName1": "СЕРГЕЙ",
|
||||
"rrPartyName2": "ГРИГОРИЙ",
|
||||
"rrPartyCountText3D": "СОПЕРНИКИ",
|
||||
"rrPartyOutText3D": "ВЫБЫЛ",
|
||||
"rrPartyTurnText3D": "ХОД",
|
||||
"rrPartyAliveText3D": "ОЖИДАЕТ",
|
||||
"rrPartyPoolText3D": "БАНК",
|
||||
"rrPartyExitText3D": "Раунд ещё не закончен.",
|
||||
"slotRefundText3D": "ВОЗВРАТ",
|
||||
"slotNetText3D": "ИТОГ",
|
||||
"clpTitle3D": "КЛЕВЕР 5x3",
|
||||
"clpTotalText3D": "МНОЖИТЕЛЬ",
|
||||
"clpNoCombo3D": "НЕТ КОМБИНАЦИЙ",
|
||||
"clpSymbolsText3D": "СИМВОЛ",
|
||||
"clpShapesText3D": "ФИГУРА",
|
||||
"clpOverlapText3D": "ФИГУРА x СИМВОЛ; СУММА",
|
||||
"clpShape0": "РЯД 3",
|
||||
"clpShape1": "РЯД 4",
|
||||
"clpShape2": "РЯД 5",
|
||||
"clpShape3": "ВЕРТИКАЛЬ",
|
||||
"clpShape4": "ДИАГОНАЛЬ",
|
||||
"clpShape5": "СТРЕЛКА ВВЕРХ",
|
||||
"clpShape6": "СТРЕЛКА ВНИЗ",
|
||||
"clpShape7": "ВЕРХНИЙ РЯД",
|
||||
"clpShape8": "НИЖНИЙ РЯД",
|
||||
"clpShape9": "ГЛАЗ",
|
||||
"clpShape10": "ДЖЕКПОТ",
|
||||
"clpSymbol0": "КЛЕВЕР",
|
||||
"clpSymbol1": "ЛИМОН",
|
||||
"clpSymbol2": "ВИШНЯ",
|
||||
"clpSymbol3": "КОЛОКОЛ",
|
||||
"clpSymbol4": "АЛМАЗ",
|
||||
"clpSymbol5": "СУНДУК",
|
||||
"clpSymbol6": "СЕМЬ",
|
||||
"slotTripleText3D": "ЦЕНТР: ТРИ ОДИНАКОВЫХ",
|
||||
"pyrExit3D": "В ХОЛЛ",
|
||||
"pyrTitle3D": "ПИРАМИДА",
|
||||
"pyrBreakText3D": "РАЗБИТИЕ",
|
||||
"pyrTurnText3D": "ХОД",
|
||||
"pyrCueText3D": "БИТОК",
|
||||
"pyrGuideText3D": "ПРИЦЕЛ",
|
||||
"pyrPenaltyText3D": "ШТРАФНОЙ ШАР",
|
||||
"pyrChoiceText3D": "ПОСЛЕ ШТРАФА",
|
||||
"pyrPlayText3D": "ИГРАТЬ",
|
||||
"pyrPassText3D": "ПЕРЕДАТЬ",
|
||||
"pyrRackText3D": "ПЕРЕБИТЬ",
|
||||
"pyrTheirBreakText3D": "ЕГО УДАР",
|
||||
"pyrNoContactText3D": "НЕТ КАСАНИЯ",
|
||||
"pyrBadBreakText3D": "НЕВЕРНЫЙ РАЗБОЙ",
|
||||
"pyrBadEndText3D": "НЕВЕРНЫЙ УДАР",
|
||||
"pyrPlayerName3D": "ВЫ",
|
||||
"pyrAIName3D": "ИИ",
|
||||
"pyrSkipText3D": "ПРОПУСК"
|
||||
}
|
||||
|
|
|
|||
BIN
assets/sprites/clover/cabinet-v1.png
Normal file
|
After Width: | Height: | Size: 2 MiB |
3
assets/sprites/clover/prompts.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"tool": "built-in image_gen"
|
||||
}
|
||||
BIN
assets/sprites/clover/symbols-v1.png
Normal file
|
After Width: | Height: | Size: 1 MiB |
BIN
assets/sprites/pyramid/balls-v1.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
6
assets/sprites/pyramid/prompts.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"mode": "built-in image_gen",
|
||||
"table": "Use case: stylized-concept. Asset type: opaque 4:3 overhead game background for Russian pyramid billiards inside the existing ornate retro casino. Precisely top-down orthographic view, never perspective: one full long wooden Russian billiards table, rich dark burgundy polished wood rails, dark emerald cloth, warm brass sights, broad rounded wood corners, realistic cushions and restrained reflections. Crisp detailed Doom-era pixel-painted bitmap art, not photoreal, not vectors. Playable cloth is a completely empty clean rectangle at x9.375% to90.625% of canvas and y20.833% to75%; this rectangle has exactly 2:1 proportions. No balls, no cue, no people, no lettering, no lights painted on cloth, no symbols. Six small black pocket mouths, corners and midpoints of the two long sides, narrow Russian pyramid pockets, not enormous pool holes. Rails around cloth, hints of crimson casino carpet beyond. Leave top 8% and bottom 16% as dark quiet framing for game HUD. All four table edges visible, table fills most of screen. Consistent pixel textures and physically coherent furniture, no skew or vanishing point, no watermark.",
|
||||
"table_narrow_edit": "Edit target: supplied Russian billiard overhead table bitmap. Change only the six pocket mouths and immediately adjoining green cushion noses. Reduce all six black pocket-mouth widths and heights to about 50% of their current size, creating genuinely narrow Russian pyramid pockets. Extend the same green felt cushion noses towards these smaller holes, preserving realistic brass collars and shadows. Keep all six pocket centers at exactly the same positions. Preserve every other pixel-art design, orthographic camera, table proportions, wood, carpet, colours, framing, and empty cloth. No balls, no cue, no new objects, no text or watermark. This remains a crisp pixel-painted casino game background, not a photo.",
|
||||
"balls": "Use case: stylized-concept. Asset type: transparent 4 by 2 equal square cell game sprite atlas with exactly eight Russian billiard ball sprites viewed from directly above, perfectly circular matching anchor/diameter. Top row four ivory white glossy phenolic billiard balls, bottom row four golden amber yellow cue balls. Four slightly different rotation/reflection poses of the same ball, subtle varied surface details; no deformations, no number markings or text. Consistent upper-left warm highlight, softly shaded lower-right edge and faint ivory and honey material tone, high-contrast crisp readable spherical silhouettes, Doom-era richly shaded pixel-painted game style. Each ball fully isolated in its cell with generous transparent gutters, same size and center, no cast shadows extending beyond ball, no background, no grid, no checkerboard, no border, no watermark. This is Russian pyramid: no coloured solids/stripes, only four whites and four identical amber cue ball rotation poses."
|
||||
}
|
||||
BIN
assets/sprites/pyramid/table-v1.png
Normal file
|
After Width: | Height: | Size: 2 MiB |
BIN
assets/sprites/pyramid/table-v2.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
assets/sprites/roulette/participants-v1.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
assets/sprites/tables/blackjack-guests-v1.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
assets/sprites/tables/blackjack-room-v1.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
bin/poker.exe
|
|
@ -8,7 +8,7 @@ namespace AssemblerCasinoLauncher
|
|||
{
|
||||
static class Program
|
||||
{
|
||||
const string ExpectedPokerSha256 = "6DE8E29E8A8FCC60C2FB297348BAD5E20697611317EF53C7E5A258BDCADAB657";
|
||||
const string ExpectedPokerSha256 = "7E7165F5B9287FCF0F7A7E8F526DD23C0DA5F3A6CF72F08D1A40EB548FFCD428";
|
||||
|
||||
[STAThread]
|
||||
static void Main()
|
||||
|
|
|
|||
10997
casino3d.inc
BIN
dist/Assembler Casino.exe
vendored
71
docs/native-blackjack-party.md
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# Native Blackjack: Shared Table
|
||||
|
||||
## Implemented
|
||||
|
||||
The graphical blackjack table can seat the player and zero to three AI guests,
|
||||
with a house dealer. The existing solo mode remains the default. Before a hand,
|
||||
the four numbered controls select the guest count (also keys 0, 1, 2, 3).
|
||||
Selection is locked until the hand has ended. Choosing a different count after
|
||||
a result clears that displayed hand without touching the wallet.
|
||||
|
||||
All seats receive actual identities from one shuffled 52-card deck. The deal
|
||||
is round-robin, followed by the player's turn, timed guest decisions and the
|
||||
dealer's turn. Each guest has a separate hand, virtual stake and result.
|
||||
Guest stakes do not come from the player's balance. Guests do not yet have
|
||||
persistent wallets or bring the hall visitor's identity to their table seat.
|
||||
|
||||
Tolya is cautious, Sergey hits more aggressively, and Alisa adapts her stopping
|
||||
threshold to the dealer's upcard. A two-card eleven can double against an
|
||||
appropriate upcard. Decisions never examine the hidden dealer card, another
|
||||
seat's hand or future deck cards. These are limited personality strategies,
|
||||
not a complete optimal blackjack strategy chart. Dealer stands on all 17s;
|
||||
player blackjack pays 3:2, pushes return the deducted stake.
|
||||
|
||||
A player bust or natural no longer truncates the guests' turns. A dealer
|
||||
natural resolves all seats immediately. The existing exit confirmation freezes
|
||||
the table and forfeits only the player's stake on confirmation. Settlement and
|
||||
NPC challenge progress happen once for the player, never once per guest.
|
||||
|
||||
## Artwork
|
||||
|
||||
`assets/sprites/tables/blackjack-guests-v1.png` was generated with the built-in
|
||||
image generator as one transparent three-column, two-row sprite sheet.
|
||||
Each adult character has an attentive pose and a card-request gesture.
|
||||
`tools/generators/pack_blackjack_guests.py` normalizes its six cells into
|
||||
160-by-160 BGRA frames in `assets/animations/tables/blackjack-guests-v1.bin`.
|
||||
These are two poses per guest, not a full continuous character animation.
|
||||
Native timed card flights and queued dealer-hand sprites animate each draw.
|
||||
`blackjack-room-v1.png` and its compiled ANM1 background put the guests behind
|
||||
the far wooden rim instead of drawing their bodies directly on the felt.
|
||||
|
||||
Generation prompt: detailed hand-painted Doom-era pixel sprites, transparent
|
||||
background, three seated adult guests (bald gray-suited man, dark-haired navy-
|
||||
jacketed man, auburn-haired emerald-dressed woman); identical anchors and scale
|
||||
across attentive/extended-hand rows; warm amber light, burgundy shadows; no
|
||||
table, cards, chips, chairs, text or cross-cell overlap.
|
||||
|
||||
Room prompt: empty first-person vintage casino background in the same detailed
|
||||
pixel style; three empty burgundy chairs behind a wooden blackjack-table rim
|
||||
at 52% canvas height, green felt below, front padded rim at 90%; dark wood,
|
||||
brass lights, no people, text or cards. The built-in generator's first room
|
||||
plate was edited to lower the far rim to the intended midpoint.
|
||||
|
||||
## Verification
|
||||
|
||||
`tools/tests/blackjack_party_test.inc` runs in the native action suite:
|
||||
600 complete hands across all three guest counts; exact deck consumption and
|
||||
card uniqueness; bounded counts; independent player payout; natural/push/bust;
|
||||
no hidden-card dependence; actual mouse and keyboard selection; safe exit and
|
||||
frozen timers; render purity and six framebuffer captures.
|
||||
|
||||
`check_blackjack_party.py --parity` compares the tested and shipping MASM
|
||||
procedures and inspects the native captures. `test_blackjack_party.ps1` is a
|
||||
focused native probe linked against the action-test object.
|
||||
|
||||
## Still Pending
|
||||
|
||||
Native three/four-player poker, Russian roulette and Buckshot are separate
|
||||
features. They are not implemented by this blackjack work, and the old console
|
||||
four-seat poker loop is not connected to the graphical table. Poker still needs
|
||||
correct multiplayer betting, all-ins, side pots and tie splits before that
|
||||
loop can become a graphical game.
|
||||
67
docs/native-clover.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# Native Clover 5x3
|
||||
|
||||
The runtime is MASM x86 only. `native_clover.inc` owns input, five timed reel
|
||||
strips, clipping, final-board evaluation, settlement, paid-combo selection and
|
||||
rendering. The original assembly `EvaluateSlotCombos` is reused directly; the
|
||||
console `GameSlot`, its sleeps, console output and payout functions are never
|
||||
called by this mode.
|
||||
|
||||
## Rules
|
||||
|
||||
Fifteen final symbols are sampled once when the stake is debited. Symbol values:
|
||||
clover 3, lemon 2, cherries 2, bell 3, diamond 5, chest 5, seven 7.
|
||||
Each paid pattern contributes its factor times its symbol value. Contributions
|
||||
are added; a pattern entirely covered by earlier paid patterns is not paid
|
||||
again. Original order: jackpot, eye, sky/earth, up/down arrows, rows 5, rows 4,
|
||||
verticals, diagonals, rows 3. The jackpot is additive, matching the original
|
||||
game, not a replacement for the remaining matches.
|
||||
|
||||
Displayed multipliers and credited payouts include any returned stake. The
|
||||
separate net field is actual credit minus the frozen stake. A bank-cap-clipped
|
||||
payout displays only the money actually credited. The bank cap is 1,000,000,000.
|
||||
777 uses the same gross/net convention, with neutral feedback for a stake
|
||||
refund, not victory feedback. Its unchanged strip/table has theoretical gross
|
||||
RTP 90.025% under independent uniform stop selection; this is not a guarantee
|
||||
for the actual pseudo-random generator or any individual session.
|
||||
|
||||
## Interaction
|
||||
|
||||
Space/Enter spins, W/S or Up/Down change the idle stake, P opens/closes the pay
|
||||
table, Left/Right select an actually paid combo. All controls have clickable
|
||||
equivalents. Escape first closes the pay table; during a paid spin it queues
|
||||
leaving until settlement/save completes, otherwise it returns to the hall.
|
||||
No pause menu or console fallback is opened.
|
||||
|
||||
The result grid highlights the selected paid mask, with its type, multiplier,
|
||||
index/count, aggregate multiplier, gross payout and net separately. Only the
|
||||
middle line of the separate 777 machine pays; its payout panel says the stake
|
||||
is included.
|
||||
|
||||
## Assets
|
||||
|
||||
Generated with the built-in image generator, then copied to
|
||||
`assets/sprites/clover/cabinet-v1.png` and `symbols-v1.png`. The cabinet is opaque
|
||||
640x480, symbols seven alpha-tested 56x56 frames. `pack_clover_assets.py` is an
|
||||
offline packer, not a non-assembly game implementation.
|
||||
|
||||
Cabinet prompt: wide front-facing Clover machine in a richly furnished retro
|
||||
casino, emerald enamel/worn brass/crimson trim, crisp textured Doom-era pixel
|
||||
art; one large blank near-black rectangular reel bay, no baked symbols,
|
||||
dividers, letters or people, straight-on framing.
|
||||
Symbol prompt: transparent equal-cell 4x2 pixel-painted atlas, clover/lemon/
|
||||
cherries/bell on top, diamond/chest/red seven below, final cell empty; isolated,
|
||||
centered, consistent apparent size and readable silhouettes, no grid/background.
|
||||
|
||||
## Verification And Scope
|
||||
|
||||
Independent offline fixture oracle covers 553 boards, including all seven
|
||||
jackpots and each pattern. Native tests cover 500 paid spins at four update
|
||||
rates, frozen RNG/stake, exact final tape rows, monotonic stopping, queued exit,
|
||||
idempotent payout, bank cap, missing funds and six framebuffer captures.
|
||||
`check_clover.py --parity` checks assets, real framebuffer clipping, all fifteen
|
||||
complete cells, selected paid-mask changes and tested/shipping assembly code.
|
||||
|
||||
Native talisman modifiers and legacy console achievement/dance side effects
|
||||
are not ported by this change. NPC challenges count native slot rounds and
|
||||
classify only positive net results as wins. No claim of completing every legacy
|
||||
Clover feature or its balance is made.
|
||||
|
|
@ -43,6 +43,12 @@ queued departure and result persistence. Six framebuffer captures cover draft,
|
|||
launch, fast/slow rotation, landing and result. The shipping loader probe also
|
||||
loads/frees wheel packs from both the project root and TEMP.
|
||||
|
||||
Additional native captures cover all 37 settled results and isolated distant
|
||||
and rotating labels. The offline checker compares every foreground digit pixel
|
||||
with an independent font mask, verifies the large central result, and checks
|
||||
that labels never overlap at any of the 512 rotation angles. Small labels write
|
||||
physical framebuffer pixels directly; they do not use the coarser UI grid.
|
||||
|
||||
The dealer background is currently a static pose. This is a native animated
|
||||
wheel/table scene, not a complete animated croupier performance or a physical
|
||||
simulation of a freely rolling ball.
|
||||
|
|
|
|||
59
docs/native-russian-party.md
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# Native Russian Roulette: Multiple Opponents
|
||||
|
||||
## Rules
|
||||
|
||||
The existing one-opponent game remains the default. Ready-screen controls select
|
||||
one, two or three opponents; Left/Right changes the selection. The existing
|
||||
1/2/3 keys still choose the number of loaded cartridges. Mouse controls also
|
||||
start the round, fire on the player's turn, and open the exit confirmation.
|
||||
|
||||
The round locks its participant count and player's stake at the start. In the
|
||||
group variant, all participants use one cylinder in cyclic order. Each takes
|
||||
their own turn; there is no selectable target. A live shot consumes that loaded
|
||||
round and removes the current participant. Empty chambers pass to the next
|
||||
remaining participant, skipping eliminated seats. The last surviving player
|
||||
receives the initial stake times the initial participant count. Opponent stakes
|
||||
are virtual casino stakes, not withdrawals from the player's account.
|
||||
|
||||
An exhausted cylinder is reloaded and spun without another payment. Reloading
|
||||
does not restore eliminated opponents or change the locked pool. The player's
|
||||
elimination preserves the existing glitch/dark/G-man/return sequence. The match
|
||||
is recorded once for NPC challenges; intermediate opponent eliminations are
|
||||
not extra paid wins. Confirmed early exit forfeits the already-paid stake.
|
||||
|
||||
Escape opens the shared leave/continue dialog in both solo and party modes;
|
||||
the dialog freezes the scene and cylinder. Cancelling resumes the same turn.
|
||||
Leaving after settlement does not make a second payout or challenge event.
|
||||
|
||||
## Graphics
|
||||
|
||||
Three distinct neutral seated opponents use six frames from
|
||||
`assets/sprites/roulette/participants-v1.png`, generated with the built-in image
|
||||
generator and packed offline into `assets/animations/roulette/participants-v1.bin`.
|
||||
The active seat is named/highlighted; an eliminated seat fades and becomes empty.
|
||||
The existing first-person player and cylinder animations are retained.
|
||||
|
||||
The party view passes the existing revolver along the tabletop. The opponents
|
||||
currently have idle/conversational poses, not complete individual cinematic
|
||||
firing animations. The attempted new firing-pose sheet was rejected by the
|
||||
image tool and is not a shipped asset. No replacement has been disguised as a
|
||||
full new shooting animation. One-opponent firing remains the existing scene.
|
||||
|
||||
Neutral sprite prompt: three waist-up adult casino guests, bald waistcoated
|
||||
man, dark-haired charcoal-jacketed man, older gray-haired brown-jacketed man;
|
||||
three columns by two rows, attentive idle and calm palm-up conversation;
|
||||
same identity/scale/anchors, transparent background, crisp late-1990s pixel
|
||||
sprites, amber light and crimson shadows; no objects, weapons, wounds or text.
|
||||
|
||||
## Verification
|
||||
|
||||
`russian_party_test.inc` covers 600 complete group matches at 16/50/250 ms
|
||||
updates, 1..3 loaded rounds, elimination order, unchanged cylinder between
|
||||
empty chambers, reload-without-payment, locked-pool settlement, render purity,
|
||||
all active pre-result exit phases, zero bank and invalid bullet count.
|
||||
The existing 2000 solo-round tests still run. Native captures and tested/shipping
|
||||
procedure parity are checked by `check_russian_party.py --parity`.
|
||||
|
||||
The runtime remains MASM. Python only packs assets and checks captures;
|
||||
the existing C# launcher remains packaging, not game code. Multiplayer poker
|
||||
and Buckshot are still separate unfinished features.
|
||||
|
|
@ -14,7 +14,10 @@ stake is charged; animation and repeated renderer calls cannot reroll them.
|
|||
Three matches pay gross multipliers: seven 100, cherries 8, lemon 10, bell 15,
|
||||
BAR 25, grapes 12, diamond 60 and crown 150. Exactly two cherries pay 2x;
|
||||
any other exact pair returns 1x. No match pays nothing. Gross payouts include
|
||||
the charged stake. Under uniformly sampled stops the configured return is
|
||||
the charged stake. The footer separates actual credited payout from signed net
|
||||
profit/loss. An exact non-cherry pair is a neutral stake refund, with no victory
|
||||
sound or winning-line flash. The pay table identifies the middle paying line.
|
||||
Under independently and uniformly sampled stops the configured return is
|
||||
7202 / 8000 = 90.025%; this is not a guarantee of individual-session results.
|
||||
|
||||
Stake choices are 10, 50, 100, 500, 1000, 5000 and 10000. The native bank cap
|
||||
|
|
@ -59,6 +62,6 @@ the shipping and test COFF code for every slot handler.
|
|||
`test_street_asset_paths.ps1` also initializes/frees the shipping native slot
|
||||
cabinet from project-root and TEMP working directories, without launching a window.
|
||||
|
||||
CloverPit, talisman effects, native achievements and slot-specific profile
|
||||
statistics still need separate integration; the native 777 does not call their
|
||||
legacy console implementations.
|
||||
CloverPit now has a separate native 5x3 machine; see `native-clover.md`. Talisman
|
||||
effects, native achievements and slot-specific profile statistics still need
|
||||
separate integration; neither machine calls their legacy console implementations.
|
||||
|
|
|
|||
53
docs/npc-life.md
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# Native Visitors and Contracts
|
||||
|
||||
The graphical runtime remains MASM. The user's six personality records in
|
||||
`npc_mind_data.inc` are retained. The visible people now read the positions of
|
||||
those records instead of a separate, unrelated square-loop animation.
|
||||
|
||||
`npc_life.inc` owns bounded 32x32 BFS navigation, millisecond walking with
|
||||
fractional carry, standing, seated lounge visits, entrance departures and
|
||||
replacement visitors. All proposed steps check the existing body-clearance,
|
||||
furniture/stage collision rules, the player and other visitors. A blocked person
|
||||
stops animating their feet and chooses another destination after waiting.
|
||||
The six active slots alternate between twelve identities. Standing/walking and
|
||||
seated poses use the existing interior sprite pack; a full animated transition
|
||||
into a chair and additional directional interior poses are not implemented yet.
|
||||
Exterior people use outdoor sprites and long sidewalk routes, not courtyard
|
||||
pacing or indoor guest sprites.
|
||||
|
||||
Press E when the conversation prompt appears. The owned graphical modal has
|
||||
accept, reward and close commands. Mouse, 1/2, Enter, 0 and Escape work without
|
||||
console input. The conversation holds the scene while it is open.
|
||||
|
||||
Twelve contract types cover played/won rounds of native coin, blackjack, poker,
|
||||
European roulette, 777 and Durak. The any-round contract also counts Russian
|
||||
roulette, Buckshot, dice, cups and skill checks. Only settled paid rounds count, with wins
|
||||
requiring a positive result rather than a push. Progress starts after acceptance;
|
||||
tasks remain associated with visitor identity even while that person is absent.
|
||||
Offers rotate with the local calendar and visitors. Rewards range from $150 to
|
||||
$700 and are capped by the game's existing billion-dollar balance limit.
|
||||
|
||||
Each local save has a companion `.npc` journal. It contains a date, bounded
|
||||
accepted/claimed masks, capped progress and a checksum. Truncated, malformed,
|
||||
wrong-date and cross-profile journals are not imported. Completed contracts
|
||||
cannot be claimed twice after closing/reopening the dialog or restarting.
|
||||
Journal write failures do not award repeatable money. The existing wallet save
|
||||
and companion journal are separate writes; an abrupt power loss between them
|
||||
can lose the reward credit, so this is not a transactional banking system.
|
||||
The original save format and the legacy forty-task daily pool are unchanged.
|
||||
|
||||
Native tests exercise ten reachable destinations, equal-time movement at three
|
||||
update rates, two minutes of body-clearance checks for all six visitors, capped
|
||||
progress, early/double claims, persistence, profile isolation, day rollover,
|
||||
mouse dialog commands and Escape. They use only journals inside build fixtures.
|
||||
`check_npc_life.py --parity` checks three native framebuffer captures and
|
||||
tested/shipping procedure parity.
|
||||
|
||||
## Multiplayer Tables
|
||||
|
||||
The user's legacy four-seat poker/personality code is preserved. It is not
|
||||
called from the graphical casino because it uses console input/output. The
|
||||
existing native tables remain heads-up. Native three/four-seat poker needs
|
||||
proper repeated betting turns, ties, all-ins/side pots, exit settlement and
|
||||
seated opponent rendering before it can replace that loop. Russian roulette
|
||||
and Buckshot likewise still use their existing two-actor scenes.
|
||||
BIN
poker.exe
BIN
poker.obj
|
|
@ -4,7 +4,10 @@ POOL_STRIKE equ 1
|
|||
POOL_MOVING equ 2
|
||||
POOL_HAND equ 3
|
||||
POOL_RESULT equ 4
|
||||
POOL_RADIUS equ 5*FP_1
|
||||
POOL_RADIUS equ FP_1*5/2
|
||||
POOL_DIAMETER equ 5*FP_1
|
||||
POOL_PENALTY equ 5
|
||||
POOL_CHOICE equ 6
|
||||
InitPool3D PROTO
|
||||
HandlePool3D PROTO
|
||||
RenderPool3D PROTO
|
||||
|
|
@ -25,8 +28,10 @@ poolColors3D dd 00F0E8D3h,00D4B524h,00304EADh,00B72B36h,006A438Ch,00DD8030h,003B
|
|||
poolRackOrder3D dd 1,9,2,3,8,10,11,4,12,5,6,13,7,14,15
|
||||
poolPocketX3D dd 30*FP_1,160*FP_1,290*FP_1,30*FP_1,160*FP_1,290*FP_1
|
||||
poolPocketY3D dd 50*FP_1,50*FP_1,50*FP_1,180*FP_1,180*FP_1,180*FP_1
|
||||
poolJawX3D dd 42*FP_1,30*FP_1,145*FP_1,175*FP_1,290*FP_1,278*FP_1,42*FP_1,30*FP_1,145*FP_1,175*FP_1,290*FP_1,278*FP_1
|
||||
poolJawY3D dd 50*FP_1,62*FP_1,58*FP_1,58*FP_1,62*FP_1,50*FP_1,180*FP_1,168*FP_1,172*FP_1,172*FP_1,168*FP_1,180*FP_1
|
||||
poolJawX3D dd FP_1*137/4,30*FP_1,157*FP_1,163*FP_1,290*FP_1,FP_1*1143/4
|
||||
dd FP_1*137/4,30*FP_1,157*FP_1,163*FP_1,290*FP_1,FP_1*1143/4
|
||||
poolJawY3D dd 50*FP_1,FP_1*217/4,50*FP_1,50*FP_1,FP_1*217/4,50*FP_1
|
||||
dd 180*FP_1,FP_1*703/4,180*FP_1,180*FP_1,FP_1*703/4,180*FP_1
|
||||
poolState3D dd POOL_AIM
|
||||
poolPlayer3D dd 0
|
||||
poolAI3D dd 1
|
||||
|
|
@ -64,3 +69,4 @@ poolBallText3D db 216,192,208,0
|
|||
poolPocketText3D db 203,211,199,192,0
|
||||
poolGroupTexts3D dd OFFSET poolOpenText3D,OFFSET poolSolidsText3D,OFFSET poolStripesText3D
|
||||
.code
|
||||
include src_graphics\pyramid_data.inc
|
||||
|
|
|
|||
|
|
@ -230,6 +230,7 @@ bs_finish_win:
|
|||
jbe @F
|
||||
mov bankroll, 1000000000
|
||||
@@:
|
||||
invoke NpcRecordRound3D,7,1
|
||||
call SaveProgress3D
|
||||
ret
|
||||
bs_finish_lose:
|
||||
|
|
@ -237,6 +238,7 @@ bs_finish_lose:
|
|||
mov bs3d_result, BS_LOSE
|
||||
mov bs3d_victim, 0
|
||||
mov bs3d_timer, 800
|
||||
invoke NpcRecordRound3D,7,0
|
||||
call SaveProgress3D
|
||||
bs_finish_done:
|
||||
ret
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
; All runtime rendering/gameplay is native. Artwork and rank tables are binary assets.
|
||||
FreeCardTableAssets3D PROC
|
||||
call FreeBJParty3D
|
||||
cmp cardTablePixels3D, 0
|
||||
je @F
|
||||
invoke HeapFree, cardTableHeap3D, 0, cardTablePixels3D
|
||||
|
|
|
|||
|
|
@ -119,8 +119,13 @@ LeaveCardTable3D PROC
|
|||
jmp card_leave_hall
|
||||
@@:
|
||||
cmp engineMode, MODE_DURAK
|
||||
jne card_leave_hall
|
||||
jne @F
|
||||
invoke NativeDurakSettle3D, 1
|
||||
jmp card_leave_hall
|
||||
@@:
|
||||
cmp engineMode,MODE_RUSSIAN
|
||||
jne card_leave_hall
|
||||
call AbortRussianRound3D
|
||||
card_leave_hall:
|
||||
mov cardExitActive3D, 0
|
||||
mov paused3D, 0
|
||||
|
|
@ -146,6 +151,12 @@ RequestCardExit3D ENDP
|
|||
|
||||
; Called by the engine's Escape dispatch, before the generic pause branch.
|
||||
CardTableEscape3D PROC
|
||||
cmp engineMode,MODE_NPC_DIALOG
|
||||
jne @F
|
||||
call CloseNpcDialog3D
|
||||
mov eax,1
|
||||
ret
|
||||
@@:
|
||||
cmp engineMode, MODE_COIN
|
||||
jne @F
|
||||
call CoinEscape3D
|
||||
|
|
@ -163,12 +174,20 @@ CardTableEscape3D PROC
|
|||
call SlotEscape3D
|
||||
mov eax,1
|
||||
ret
|
||||
@@:
|
||||
cmp engineMode, MODE_CLOVER
|
||||
jne @F
|
||||
call CloverEscape3D
|
||||
mov eax,1
|
||||
ret
|
||||
@@:
|
||||
cmp engineMode, MODE_POKER
|
||||
je card_escape_handle
|
||||
cmp engineMode, MODE_BLACKJACK
|
||||
je card_escape_handle
|
||||
cmp engineMode, MODE_DURAK
|
||||
je card_escape_handle
|
||||
cmp engineMode, MODE_RUSSIAN
|
||||
jne card_escape_other
|
||||
card_escape_handle:
|
||||
cmp cardExitActive3D, 0
|
||||
|
|
@ -283,6 +302,8 @@ TableBusy3D PROC
|
|||
je table_busy_russian
|
||||
cmp eax, MODE_SLOTS
|
||||
je table_busy_slots
|
||||
cmp eax, MODE_CLOVER
|
||||
je table_busy_clover
|
||||
cmp eax, MODE_ROULETTE
|
||||
je table_busy_wheel
|
||||
cmp eax, MODE_COIN
|
||||
|
|
@ -334,6 +355,10 @@ table_busy_slots:
|
|||
cmp slotSpinState, 1
|
||||
je table_is_busy
|
||||
jmp table_not_busy
|
||||
table_busy_clover:
|
||||
cmp clpState3D,SLOT_SPIN
|
||||
je table_is_busy
|
||||
jmp table_not_busy
|
||||
table_busy_wheel:
|
||||
cmp roulState, 1
|
||||
je table_is_busy
|
||||
|
|
|
|||
|
|
@ -299,6 +299,11 @@ RenderNativePoker3D ENDP
|
|||
|
||||
RenderNativeBlackjack3D PROC uses ebx esi edi
|
||||
local hand:DWORD,nCards:DWORD,y:DWORD,spacing:DWORD,startX:DWORD,hidden:DWORD,flipCard:DWORD
|
||||
cmp cbBotCount3D, 0
|
||||
je @F
|
||||
call RenderBJParty3D
|
||||
ret
|
||||
@@:
|
||||
call RenderCardTable3D
|
||||
invoke DrawTableHeader3D, OFFSET cbTitle3D, cbStake3D
|
||||
xor eax, eax
|
||||
|
|
@ -461,6 +466,7 @@ bj_render_next_card:
|
|||
invoke DrawString8x8, 116, 135, cbResults3D[eax*4], 00EFD583h
|
||||
bj_render_buttons:
|
||||
call DrawQueuedTableHand3D
|
||||
call DrawBJPartySelector3D
|
||||
cmp cbError3D, 0
|
||||
je @F
|
||||
invoke DrawString8x8, 80, 135, OFFSET textNoCash3D, 00F89880h
|
||||
|
|
@ -509,7 +515,12 @@ card_exit_dim:
|
|||
loop card_exit_dim
|
||||
invoke DrawBoxBorder, 20, 64, 280, 120, 00151D20h, 00D5C79Eh, 1
|
||||
invoke DrawString8x8, 104, 78, OFFSET cardExitTitle3D, 00F2E4BCh
|
||||
invoke DrawString8x8, 60, 104, OFFSET cardExitWarning3D, 00D8DFDDh
|
||||
mov ecx,OFFSET cardExitWarning3D
|
||||
cmp engineMode,MODE_RUSSIAN
|
||||
jne @F
|
||||
mov ecx,OFFSET rrPartyExitText3D
|
||||
@@:
|
||||
invoke DrawString8x8, 60, 104, ecx, 00D8DFDDh
|
||||
invoke DrawString8x8, 72, 120, OFFSET cardExitStake3D, 00F4B6A4h
|
||||
mov ebx, 00D5C79Eh
|
||||
mov esi, 00556555h
|
||||
|
|
|
|||
|
|
@ -152,11 +152,11 @@ cityEntryWoman3D LABEL BYTE
|
|||
cityObjectsEnd3D LABEL BYTE
|
||||
.errnz ((cityObjectsEnd3D-cityObjects3D)/SIZEOF CityProp3D)-CITY_PROP_COUNT
|
||||
cityWalkRoutes3D CityWalkRoute3D <(cityNearMan3D-cityObjects3D)/SIZEOF CityProp3D,10*FP_1,28*FP_1,FP_1*253/20,0,32000,0,140>
|
||||
CityWalkRoute3D <(cityFarWoman3D-cityObjects3D)/SIZEOF CityProp3D,10*FP_1,28*FP_1,FP_1*169/10,32000,32000,16,160>
|
||||
CityWalkRoute3D <(cityFarWoman3D-cityObjects3D)/SIZEOF CityProp3D,10*FP_1,28*FP_1,16*FP_1+FP_HALF,32000,32000,16,160>
|
||||
CityWalkRoute3D <(cityNearWoman3D-cityObjects3D)/SIZEOF CityProp3D,11*FP_1,27*FP_1,FP_1*63/5,21000,30000,16,155>
|
||||
CityWalkRoute3D <(cityFarMan3D-cityObjects3D)/SIZEOF CityProp3D,10*FP_1,28*FP_1,FP_1*337/20,13000,34000,0,145>
|
||||
CityWalkRoute3D <(cityEntryMan3D-cityObjects3D)/SIZEOF CityProp3D,20*FP_1+FP_1/5,21*FP_1+FP_1/5,9*FP_1,0,4000,0,140>
|
||||
CityWalkRoute3D <(cityEntryWoman3D-cityObjects3D)/SIZEOF CityProp3D,23*FP_1+FP_1*4/5,24*FP_1+FP_1*4/5,9*FP_1,4000,5200,16,160>
|
||||
CityWalkRoute3D <(cityFarMan3D-cityObjects3D)/SIZEOF CityProp3D,10*FP_1,28*FP_1,16*FP_1+FP_HALF,13000,34000,0,145>
|
||||
CityWalkRoute3D <(cityEntryMan3D-cityObjects3D)/SIZEOF CityProp3D,11*FP_1,29*FP_1,FP_1*253/20,4000,31000,0,140>
|
||||
CityWalkRoute3D <(cityEntryWoman3D-cityObjects3D)/SIZEOF CityProp3D,12*FP_1,30*FP_1,16*FP_1+FP_HALF,18000,30000,16,160>
|
||||
IFDEF CASINO_ACTION_TEST
|
||||
cityVisiblePixels3D dd CITY_PROP_COUNT dup(0)
|
||||
ENDIF
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ InitNativeBlackjack3D PROC
|
|||
mov cbDealerCount3D, 0
|
||||
mov cbStake3D, 0
|
||||
mov cbError3D, 0
|
||||
call InitBJParty3D
|
||||
call ClearKeys3D
|
||||
ret
|
||||
InitNativeBlackjack3D ENDP
|
||||
|
|
@ -59,6 +60,8 @@ NativeBJSettle3D PROC result:DWORD
|
|||
mov cbVisible3D, 1
|
||||
mov eax, result
|
||||
mov cbOutcome3D, eax
|
||||
call ResolveBJParty3D
|
||||
mov eax, result
|
||||
cmp eax, 1
|
||||
je bj_settle_loss
|
||||
mov eax, cbStake3D
|
||||
|
|
@ -78,6 +81,14 @@ bj_settle_loss:
|
|||
invoke PlayCasinoSound3D, OFFSET soundRoundLose, 0, 1
|
||||
bj_settle_save:
|
||||
call ClearKeys3D
|
||||
xor eax,eax
|
||||
cmp cbOutcome3D,0
|
||||
sete al
|
||||
cmp cbOutcome3D,3
|
||||
jne @F
|
||||
mov eax,1
|
||||
@@:
|
||||
invoke NpcRecordRound3D,1,eax
|
||||
call SaveProgress3D
|
||||
bj_settle_done:
|
||||
ret
|
||||
|
|
@ -96,6 +107,9 @@ StartNativeBlackjack3D PROC
|
|||
mov cbStake3D, eax
|
||||
mov cbError3D, 0
|
||||
mov cbDouble3D, 0
|
||||
mov cbEarlyOutcome3D, -1
|
||||
mov cbBotsSettled3D, 0
|
||||
mov cbInitialFlights3D, 4
|
||||
mov cbVisible3D, 0
|
||||
mov cbPlayerCount3D, 2
|
||||
mov cbDealerCount3D, 2
|
||||
|
|
@ -109,6 +123,10 @@ StartNativeBlackjack3D PROC
|
|||
mov cbPlayer3D[4], eax
|
||||
mov eax, cbDeck3D[12]
|
||||
mov cbDealer3D[4], eax
|
||||
cmp cbBotCount3D, 0
|
||||
je @F
|
||||
call DealBJParty3D
|
||||
@@:
|
||||
invoke NativeBJScore3D, OFFSET cbPlayer3D, 2
|
||||
mov cbPlayerScore3D, eax
|
||||
invoke NativeBJScore3D, OFFSET cbDealer3D, 2
|
||||
|
|
@ -130,6 +148,8 @@ NativeBJHit3D PROC uses ebx
|
|||
jne bj_hit_done
|
||||
cmp cbPlayerCount3D, 12
|
||||
jae bj_hit_done
|
||||
cmp cbCursor3D, 52
|
||||
jae bj_hit_done
|
||||
mov ebx, cbCursor3D
|
||||
mov eax, cbDeck3D[ebx*4]
|
||||
mov cbCard3D, eax
|
||||
|
|
@ -146,6 +166,7 @@ HandleNativeBlackjack3D PROC uses ebx
|
|||
call HandleCardExit3D
|
||||
test eax, eax
|
||||
jnz bj_input_done
|
||||
call BJPartyInput3D
|
||||
invoke CardTableMouse3D, MODE_BLACKJACK
|
||||
cmp cardExitActive3D, 0
|
||||
jne bj_input_done
|
||||
|
|
@ -157,11 +178,18 @@ HandleNativeBlackjack3D PROC uses ebx
|
|||
je bj_ready_input
|
||||
cmp cbState3D, CB_PLAYER
|
||||
je bj_player_input
|
||||
cmp cbState3D, CB_BOTS
|
||||
jne @F
|
||||
call UpdateBJParty3D
|
||||
ret
|
||||
@@:
|
||||
mov eax, deltaTime3D
|
||||
add cbTimer3D, eax
|
||||
cmp cbState3D, CB_DEAL
|
||||
jne bj_animate_hit
|
||||
cmp cbTimer3D, TABLE_FLIGHT_MS*4
|
||||
mov eax, cbInitialFlights3D
|
||||
imul eax, TABLE_FLIGHT_MS
|
||||
cmp cbTimer3D, eax
|
||||
jb bj_input_done
|
||||
cmp cbDealerScore3D, 21
|
||||
jne bj_player_natural
|
||||
|
|
@ -175,7 +203,7 @@ HandleNativeBlackjack3D PROC uses ebx
|
|||
bj_player_natural:
|
||||
cmp cbPlayerScore3D, 21
|
||||
jne bj_begin_player
|
||||
invoke NativeBJSettle3D, 3
|
||||
invoke FinishBJPlayer3D, 3
|
||||
ret
|
||||
bj_begin_player:
|
||||
mov cbState3D, CB_PLAYER
|
||||
|
|
@ -199,7 +227,7 @@ bj_animate_hit:
|
|||
jne bj_begin_dealer
|
||||
jmp bj_begin_player
|
||||
bj_player_bust:
|
||||
invoke NativeBJSettle3D, 1
|
||||
invoke FinishBJPlayer3D, 1
|
||||
ret
|
||||
bj_animate_dealer:
|
||||
cmp cbTimer3D, 600
|
||||
|
|
@ -208,6 +236,8 @@ bj_animate_dealer:
|
|||
jae bj_compare_hands
|
||||
cmp cbDealerCount3D, 12
|
||||
jae bj_compare_hands
|
||||
cmp cbCursor3D, 52
|
||||
jae bj_compare_hands
|
||||
mov ebx, cbCursor3D
|
||||
mov eax, cbDeck3D[ebx*4]
|
||||
inc cbCursor3D
|
||||
|
|
@ -220,6 +250,11 @@ bj_animate_dealer:
|
|||
invoke PlayCasinoSound3D, OFFSET soundCards, 0, 1
|
||||
ret
|
||||
bj_compare_hands:
|
||||
cmp cbEarlyOutcome3D, -1
|
||||
je @F
|
||||
invoke NativeBJSettle3D, cbEarlyOutcome3D
|
||||
ret
|
||||
@@:
|
||||
mov eax, cbDealerScore3D
|
||||
cmp eax, 21
|
||||
ja bj_player_win
|
||||
|
|
@ -260,10 +295,7 @@ bj_player_input:
|
|||
test eax, eax
|
||||
jz bj_input_done
|
||||
bj_begin_dealer:
|
||||
mov cbVisible3D, 1
|
||||
mov cbState3D, CB_DEALER
|
||||
mov cbTimer3D, 0
|
||||
call ClearKeys3D
|
||||
invoke FinishBJPlayer3D, -1
|
||||
ret
|
||||
bj_ready_input:
|
||||
invoke Pressed3D, 26h
|
||||
|
|
@ -287,3 +319,4 @@ bj_ready_input:
|
|||
bj_input_done:
|
||||
ret
|
||||
HandleNativeBlackjack3D ENDP
|
||||
include src_graphics\native_blackjack_party.inc
|
||||
|
|
|
|||
357
src_graphics/native_blackjack_party.inc
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
InitBJParty3D PROC uses edi
|
||||
invoke LoadAnimPack3D,OFFSET cbPartyRoom3D,OFFSET cbPartyRoomPath3D
|
||||
cmp cbPartyRoom3D.frames,1
|
||||
jne bj_party_invalid_room
|
||||
cmp cbPartyRoom3D.imageWidth,SCREEN_W
|
||||
jne bj_party_invalid_room
|
||||
cmp cbPartyRoom3D.height,SCREEN_H
|
||||
je bj_party_room_ready
|
||||
bj_party_invalid_room:
|
||||
invoke FreeAnimPack3D,OFFSET cbPartyRoom3D
|
||||
bj_party_room_ready:
|
||||
cmp cbBotCount3D,3
|
||||
jbe @F
|
||||
mov cbBotCount3D,0
|
||||
@@:
|
||||
mov cbEarlyOutcome3D,-1
|
||||
mov cbBotsSettled3D,0
|
||||
mov cbBotTurn3D,0
|
||||
mov cbBotTimer3D,0
|
||||
lea edi,cbBots3D
|
||||
mov ecx,SIZEOF BJBot3D*3/4
|
||||
xor eax,eax
|
||||
rep stosd
|
||||
invoke LoadAnimPack3D,OFFSET cbPartyArt3D,OFFSET cbPartyArtPath3D
|
||||
cmp cbPartyArt3D.frames,6
|
||||
jne bj_party_invalid_art
|
||||
cmp cbPartyArt3D.imageWidth,160
|
||||
jne bj_party_invalid_art
|
||||
cmp cbPartyArt3D.height,160
|
||||
jne bj_party_invalid_art
|
||||
ret
|
||||
bj_party_invalid_art:
|
||||
call FreeBJParty3D
|
||||
ret
|
||||
InitBJParty3D ENDP
|
||||
|
||||
FreeBJParty3D PROC
|
||||
invoke FreeAnimPack3D,OFFSET cbPartyArt3D
|
||||
invoke FreeAnimPack3D,OFFSET cbPartyRoom3D
|
||||
ret
|
||||
FreeBJParty3D ENDP
|
||||
|
||||
; Round-robin: player, each guest, then dealer. Old solo order is unchanged.
|
||||
DealBJParty3D PROC uses ebx esi edi
|
||||
call InitBJParty3D
|
||||
mov eax,cbBotCount3D
|
||||
add eax,2
|
||||
shl eax,1
|
||||
mov cbInitialFlights3D,eax
|
||||
mov cbCursor3D,0
|
||||
xor edi,edi
|
||||
bj_party_deal_pass:
|
||||
mov ecx,cbCursor3D
|
||||
mov eax,cbDeck3D[ecx*4]
|
||||
mov cbPlayer3D[edi*4],eax
|
||||
inc cbCursor3D
|
||||
xor ebx,ebx
|
||||
bj_party_deal_guest:
|
||||
cmp ebx,cbBotCount3D
|
||||
jae bj_party_deal_dealer
|
||||
mov esi,ebx
|
||||
imul esi,SIZEOF BJBot3D
|
||||
add esi,OFFSET cbBots3D
|
||||
mov ecx,cbCursor3D
|
||||
mov eax,cbDeck3D[ecx*4]
|
||||
mov [esi+edi*4].BJBot3D.cards,eax
|
||||
inc cbCursor3D
|
||||
mov [esi].BJBot3D.count,2
|
||||
mov eax,cbBet3D
|
||||
mov [esi].BJBot3D.stake,eax
|
||||
inc ebx
|
||||
jmp bj_party_deal_guest
|
||||
bj_party_deal_dealer:
|
||||
mov ecx,cbCursor3D
|
||||
mov eax,cbDeck3D[ecx*4]
|
||||
mov cbDealer3D[edi*4],eax
|
||||
inc cbCursor3D
|
||||
inc edi
|
||||
cmp edi,2
|
||||
jb bj_party_deal_pass
|
||||
xor ebx,ebx
|
||||
bj_party_deal_score:
|
||||
cmp ebx,cbBotCount3D
|
||||
jae bj_party_deal_done
|
||||
mov esi,ebx
|
||||
imul esi,SIZEOF BJBot3D
|
||||
add esi,OFFSET cbBots3D
|
||||
invoke NativeBJScore3D,esi,2
|
||||
mov [esi].BJBot3D.score,eax
|
||||
inc ebx
|
||||
jmp bj_party_deal_score
|
||||
bj_party_deal_done:
|
||||
ret
|
||||
DealBJParty3D ENDP
|
||||
|
||||
BeginBJDealer3D PROC
|
||||
mov cbVisible3D,1
|
||||
mov cbState3D,CB_DEALER
|
||||
mov cbTimer3D,0
|
||||
call ClearKeys3D
|
||||
ret
|
||||
BeginBJDealer3D ENDP
|
||||
|
||||
; Keep the table alive after a player bust/natural so other seats finish.
|
||||
FinishBJPlayer3D PROC pending:DWORD
|
||||
mov eax,pending
|
||||
mov cbEarlyOutcome3D,eax
|
||||
cmp cbBotCount3D,0
|
||||
je bj_party_solo_finish
|
||||
mov cbBotTurn3D,0
|
||||
mov cbBotTimer3D,0
|
||||
mov cbState3D,CB_BOTS
|
||||
call ClearKeys3D
|
||||
ret
|
||||
bj_party_solo_finish:
|
||||
cmp pending,-1
|
||||
jne @F
|
||||
call BeginBJDealer3D
|
||||
ret
|
||||
@@:
|
||||
invoke NativeBJSettle3D,pending
|
||||
ret
|
||||
FinishBJPlayer3D ENDP
|
||||
|
||||
; No hidden dealer card, other hands, future deck cards or RNG are consulted.
|
||||
BJBotDecision3D PROC uses ebx esi slot:DWORD
|
||||
cmp slot,3
|
||||
jae bj_bot_stand
|
||||
mov esi,slot
|
||||
imul esi,SIZEOF BJBot3D
|
||||
add esi,OFFSET cbBots3D
|
||||
cmp [esi].BJBot3D.count,12
|
||||
jae bj_bot_stand
|
||||
mov eax,cbDealer3D
|
||||
xor edx,edx
|
||||
mov ecx,13
|
||||
div ecx
|
||||
lea ebx,[edx+2]
|
||||
cmp ebx,11
|
||||
jbe @F
|
||||
mov ebx,10
|
||||
@@:
|
||||
cmp edx,12
|
||||
jne @F
|
||||
mov ebx,11
|
||||
@@:
|
||||
mov eax,[esi].BJBot3D.score
|
||||
cmp eax,21
|
||||
jae bj_bot_stand
|
||||
cmp [esi].BJBot3D.count,2
|
||||
jne bj_bot_threshold
|
||||
cmp eax,11
|
||||
jne bj_bot_threshold
|
||||
cmp ebx,10
|
||||
jae bj_bot_threshold
|
||||
mov eax,2
|
||||
ret
|
||||
bj_bot_threshold:
|
||||
mov ecx,17
|
||||
cmp slot,1
|
||||
jne @F
|
||||
mov ecx,19
|
||||
@@:
|
||||
cmp slot,2
|
||||
jne @F
|
||||
cmp ebx,7
|
||||
jae @F
|
||||
mov ecx,13
|
||||
@@:
|
||||
cmp eax,ecx
|
||||
jae bj_bot_stand
|
||||
mov eax,1
|
||||
ret
|
||||
bj_bot_stand:
|
||||
xor eax,eax
|
||||
ret
|
||||
BJBotDecision3D ENDP
|
||||
|
||||
UpdateBJParty3D PROC uses ebx esi
|
||||
mov eax,deltaTime3D
|
||||
cmp eax,250
|
||||
jbe @F
|
||||
mov eax,250
|
||||
@@:
|
||||
add cbBotTimer3D,eax
|
||||
mov ebx,cbBotTurn3D
|
||||
cmp ebx,cbBotCount3D
|
||||
jae bj_bot_finish_table
|
||||
mov esi,ebx
|
||||
imul esi,SIZEOF BJBot3D
|
||||
add esi,OFFSET cbBots3D
|
||||
cmp [esi].BJBot3D.state,BJ_BOT_FLIGHT
|
||||
je bj_bot_commit
|
||||
cmp cbBotTimer3D,BJ_PARTY_MS
|
||||
jb bj_bot_tick_done
|
||||
invoke BJBotDecision3D,ebx
|
||||
test eax,eax
|
||||
jz bj_bot_finish_seat
|
||||
cmp cbCursor3D,52
|
||||
jae bj_bot_finish_seat
|
||||
cmp eax,2
|
||||
jne @F
|
||||
shl [esi].BJBot3D.stake,1
|
||||
@@:
|
||||
mov ecx,cbCursor3D
|
||||
mov eax,cbDeck3D[ecx*4]
|
||||
mov cbBotCard3D,eax
|
||||
inc cbCursor3D
|
||||
mov cbBotTimer3D,0
|
||||
mov [esi].BJBot3D.state,BJ_BOT_FLIGHT
|
||||
invoke PlayCasinoSound3D,OFFSET soundCards,0,1
|
||||
ret
|
||||
bj_bot_commit:
|
||||
cmp cbBotTimer3D,TABLE_FLIGHT_MS
|
||||
jb bj_bot_tick_done
|
||||
mov ecx,[esi].BJBot3D.count
|
||||
cmp ecx,12
|
||||
jae bj_bot_finish_seat
|
||||
mov eax,cbBotCard3D
|
||||
mov [esi+ecx*4].BJBot3D.cards,eax
|
||||
inc [esi].BJBot3D.count
|
||||
invoke NativeBJScore3D,esi,[esi].BJBot3D.count
|
||||
mov [esi].BJBot3D.score,eax
|
||||
cmp eax,21
|
||||
jae bj_bot_finish_seat
|
||||
mov eax,cbBet3D
|
||||
cmp [esi].BJBot3D.stake,eax
|
||||
ja bj_bot_finish_seat
|
||||
mov [esi].BJBot3D.state,BJ_BOT_WAIT
|
||||
mov cbBotTimer3D,0
|
||||
ret
|
||||
bj_bot_finish_seat:
|
||||
mov [esi].BJBot3D.state,BJ_BOT_DONE
|
||||
inc cbBotTurn3D
|
||||
mov cbBotTimer3D,0
|
||||
ret
|
||||
bj_bot_finish_table:
|
||||
call BeginBJDealer3D
|
||||
bj_bot_tick_done:
|
||||
ret
|
||||
UpdateBJParty3D ENDP
|
||||
|
||||
ResolveBJParty3D PROC uses ebx esi
|
||||
cmp cbBotsSettled3D,0
|
||||
jne bj_bot_resolve_done
|
||||
mov cbBotsSettled3D,1
|
||||
xor ebx,ebx
|
||||
bj_bot_resolve:
|
||||
cmp ebx,cbBotCount3D
|
||||
jae bj_bot_resolve_done
|
||||
mov esi,ebx
|
||||
imul esi,SIZEOF BJBot3D
|
||||
add esi,OFFSET cbBots3D
|
||||
mov [esi].BJBot3D.state,BJ_BOT_DONE
|
||||
mov eax,1
|
||||
mov ecx,[esi].BJBot3D.score
|
||||
cmp ecx,21
|
||||
ja bj_bot_result
|
||||
cmp cbDealerScore3D,21
|
||||
jne bj_bot_no_dealer_natural
|
||||
cmp cbDealerCount3D,2
|
||||
jne bj_bot_no_dealer_natural
|
||||
cmp ecx,21
|
||||
jne bj_bot_result
|
||||
cmp [esi].BJBot3D.count,2
|
||||
jne bj_bot_result
|
||||
mov eax,2
|
||||
jmp bj_bot_result
|
||||
bj_bot_no_dealer_natural:
|
||||
cmp ecx,21
|
||||
jne bj_bot_compare
|
||||
cmp [esi].BJBot3D.count,2
|
||||
jne bj_bot_compare
|
||||
mov eax,3
|
||||
jmp bj_bot_result
|
||||
bj_bot_compare:
|
||||
cmp cbDealerScore3D,21
|
||||
ja bj_bot_won
|
||||
cmp ecx,cbDealerScore3D
|
||||
jb bj_bot_result
|
||||
je bj_bot_pushed
|
||||
bj_bot_won:
|
||||
xor eax,eax
|
||||
jmp bj_bot_result
|
||||
bj_bot_pushed:
|
||||
mov eax,2
|
||||
bj_bot_result:
|
||||
mov [esi].BJBot3D.outcome,eax
|
||||
inc ebx
|
||||
jmp bj_bot_resolve
|
||||
bj_bot_resolve_done:
|
||||
ret
|
||||
ResolveBJParty3D ENDP
|
||||
|
||||
SetBJPartyCount3D PROC count:DWORD
|
||||
cmp count,3
|
||||
ja bj_party_count_done
|
||||
cmp cbState3D,CB_IDLE
|
||||
je @F
|
||||
cmp cbState3D,CB_RESULT
|
||||
jne bj_party_count_done
|
||||
@@:
|
||||
mov eax,count
|
||||
cmp eax,cbBotCount3D
|
||||
je bj_party_count_done
|
||||
mov cbBotCount3D,eax
|
||||
mov cbState3D,CB_IDLE
|
||||
mov cbPlayerCount3D,0
|
||||
mov cbDealerCount3D,0
|
||||
mov cbStake3D,0
|
||||
mov cbError3D,0
|
||||
call InitBJParty3D
|
||||
bj_party_count_done:
|
||||
ret
|
||||
SetBJPartyCount3D ENDP
|
||||
|
||||
BJPartyInput3D PROC uses ebx
|
||||
cmp cbState3D,CB_IDLE
|
||||
je @F
|
||||
cmp cbState3D,CB_RESULT
|
||||
jne bj_party_input_done
|
||||
@@:
|
||||
xor ebx,ebx
|
||||
bj_party_key:
|
||||
lea eax,[ebx+30h]
|
||||
invoke Pressed3D,eax
|
||||
test eax,eax
|
||||
jz @F
|
||||
invoke SetBJPartyCount3D,ebx
|
||||
ret
|
||||
@@:
|
||||
inc ebx
|
||||
cmp ebx,4
|
||||
jb bj_party_key
|
||||
cmp mouseClick3D,0
|
||||
je bj_party_input_done
|
||||
cmp mouseY3D,35
|
||||
jb bj_party_input_done
|
||||
cmp mouseY3D,51
|
||||
jae bj_party_input_done
|
||||
mov eax,mouseX3D
|
||||
sub eax,212
|
||||
jc bj_party_input_done
|
||||
cmp eax,100
|
||||
jae bj_party_input_done
|
||||
xor edx,edx
|
||||
mov ecx,25
|
||||
div ecx
|
||||
cmp edx,22
|
||||
jae bj_party_input_done
|
||||
invoke SetBJPartyCount3D,eax
|
||||
mov mouseClick3D,0
|
||||
bj_party_input_done:
|
||||
ret
|
||||
BJPartyInput3D ENDP
|
||||
|
||||
include src_graphics\native_blackjack_party_render.inc
|
||||
60
src_graphics/native_blackjack_party_data.inc
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
; Independent blackjack seats share one deck, never the player's wallet.
|
||||
CB_BOTS equ 6
|
||||
BJ_BOT_WAIT equ 0
|
||||
BJ_BOT_FLIGHT equ 1
|
||||
BJ_BOT_DONE equ 2
|
||||
BJ_PARTY_MS equ 550
|
||||
BJBot3D STRUCT
|
||||
cards dd 12 dup(0)
|
||||
count dd 0
|
||||
score dd 0
|
||||
stake dd 0
|
||||
outcome dd 0
|
||||
state dd 0
|
||||
BJBot3D ENDS
|
||||
InitBJParty3D PROTO
|
||||
FreeBJParty3D PROTO
|
||||
DealBJParty3D PROTO
|
||||
BeginBJDealer3D PROTO
|
||||
FinishBJPlayer3D PROTO :DWORD
|
||||
UpdateBJParty3D PROTO
|
||||
BJBotDecision3D PROTO :DWORD
|
||||
ResolveBJParty3D PROTO
|
||||
BJPartyInput3D PROTO
|
||||
SetBJPartyCount3D PROTO :DWORD
|
||||
RenderBJParty3D PROTO
|
||||
DrawBJPartySelector3D PROTO
|
||||
DrawBJMiniCard3D PROTO :DWORD,:DWORD,:DWORD,:DWORD
|
||||
DrawBJMiniFlight3D PROTO :DWORD,:DWORD,:DWORD,:DWORD
|
||||
.data
|
||||
cbBotCount3D dd 0
|
||||
cbBots3D BJBot3D 3 dup(<>)
|
||||
cbBotTurn3D dd 0
|
||||
cbBotTimer3D dd 0
|
||||
cbBotCard3D dd 0
|
||||
cbEarlyOutcome3D dd -1
|
||||
cbBotsSettled3D dd 0
|
||||
cbInitialFlights3D dd 4
|
||||
cbPartyArt3D AnimPack3D <>
|
||||
cbPartyArtPath3D db "assets\animations\tables\blackjack-guests-v1.bin",0
|
||||
cbPartyRoom3D AnimPack3D <>
|
||||
cbPartyRoomPath3D db "assets\animations\tables\blackjack-room-v1.bin",0
|
||||
cbPartyNames3D dd OFFSET cbPartyName0,OFFSET cbPartyName1,OFFSET cbPartyName2
|
||||
cbPartyName0 db 210,206,203,223,0
|
||||
cbPartyName1 db 209,197,208,195,197,201,0
|
||||
cbPartyName2 db 192,203,200,209,192,0
|
||||
cbBotsLabel3D db 193,206,210,219,0
|
||||
cbBotWaitText3D db 198,196,168,210,0
|
||||
cbBotHitText3D db 202,192,208,210,192,0
|
||||
cbBotStandText3D db 213,194,192,210,200,210,0
|
||||
cbBotBustText3D db 207,197,208,197,193,206,208,0
|
||||
cbBotWinText3D db 207,206,193,197,196,192,0
|
||||
cbBotLoseText3D db 207,208,206,200,195,208,219,216,0
|
||||
cbBotPushText3D db 205,200,215,220,223,0
|
||||
cbBotNaturalText3D db 193,203,221,202,196,198,197,202,0
|
||||
cbBotResults3D dd OFFSET cbBotWinText3D,OFFSET cbBotLoseText3D,OFFSET cbBotPushText3D,OFFSET cbBotNaturalText3D
|
||||
cbDealerLabel3D db 196,200,203,197,208,0
|
||||
cbPartyPlayerText3D db 194,219,0
|
||||
cbPartyDigit3D db "0",0,"1",0,"2",0,"3",0
|
||||
cbPartyX3D dd 8,120,232
|
||||
.code
|
||||
407
src_graphics/native_blackjack_party_render.inc
Normal file
|
|
@ -0,0 +1,407 @@
|
|||
DrawBJPartySelector3D PROC uses ebx esi edi
|
||||
xor edi,edi
|
||||
cmp cbState3D,CB_IDLE
|
||||
je @F
|
||||
cmp cbState3D,CB_RESULT
|
||||
jne bj_party_selector
|
||||
@@:
|
||||
mov edi,1
|
||||
bj_party_selector:
|
||||
invoke DrawString8x8,176,39,OFFSET cbBotsLabel3D,00D4C5A4h
|
||||
xor ebx,ebx
|
||||
bj_party_selector_loop:
|
||||
mov esi,ebx
|
||||
imul esi,25
|
||||
add esi,212
|
||||
mov ecx,00454D48h
|
||||
test edi,edi
|
||||
jz @F
|
||||
mov ecx,00D1B16Eh
|
||||
@@:
|
||||
mov eax,00202D26h
|
||||
cmp ebx,cbBotCount3D
|
||||
jne @F
|
||||
mov eax,003B6C59h
|
||||
@@:
|
||||
invoke DrawBoxBorder,esi,35,22,16,eax,ecx,1
|
||||
lea edx,cbPartyDigit3D[ebx*2]
|
||||
lea eax,[esi+7]
|
||||
invoke DrawString8x8,eax,39,edx,00F2E9D3h
|
||||
inc ebx
|
||||
cmp ebx,4
|
||||
jb bj_party_selector_loop
|
||||
ret
|
||||
DrawBJPartySelector3D ENDP
|
||||
|
||||
; Smaller guest cards retain an unambiguous rank and suit, never fake identities.
|
||||
DrawBJMiniCard3D PROC uses ebx esi x:DWORD,y:DWORD,card:DWORD,hidden:DWORD
|
||||
local ink:DWORD,rank:DWORD,suit:DWORD
|
||||
mov ecx,00EEEDE2h
|
||||
cmp hidden,0
|
||||
je @F
|
||||
mov ecx,004A2941h
|
||||
@@:
|
||||
invoke DrawBoxBorder,x,y,20,30,ecx,00BCA878h,1
|
||||
cmp hidden,0
|
||||
jne bj_mini_back
|
||||
mov eax,card
|
||||
xor edx,edx
|
||||
mov ecx,13
|
||||
div ecx
|
||||
mov suit,eax
|
||||
mov rank,edx
|
||||
mov ink,00191F24h
|
||||
cmp eax,1
|
||||
je @F
|
||||
cmp eax,2
|
||||
jne bj_mini_face
|
||||
@@:
|
||||
mov ink,00BF263Ch
|
||||
bj_mini_face:
|
||||
lea edx,cardRankNames3D[edx*2]
|
||||
mov eax,x
|
||||
add eax,3
|
||||
mov ecx,y
|
||||
add ecx,3
|
||||
invoke DrawString8x8,eax,ecx,edx,ink
|
||||
mov eax,x
|
||||
add eax,6
|
||||
mov edx,y
|
||||
add edx,17
|
||||
invoke DrawNativeSuit3D,eax,edx,suit,ink
|
||||
ret
|
||||
bj_mini_back:
|
||||
mov eax,x
|
||||
add eax,4
|
||||
mov edx,y
|
||||
add edx,4
|
||||
invoke DrawBoxBorder,eax,edx,12,22,004A2941h,00C9B589h,1
|
||||
ret
|
||||
DrawBJMiniCard3D ENDP
|
||||
|
||||
DrawBJMiniFlight3D PROC uses ebx x:DWORD,y:DWORD,card:DWORD,timeMs:DWORD
|
||||
local px:DWORD,py:DWORD
|
||||
mov ebx,timeMs
|
||||
cmp ebx,TABLE_FLIGHT_MS
|
||||
jbe @F
|
||||
mov ebx,TABLE_FLIGHT_MS
|
||||
@@:
|
||||
mov eax,x
|
||||
sub eax,170
|
||||
imul eax,ebx
|
||||
cdq
|
||||
mov ecx,TABLE_FLIGHT_MS
|
||||
idiv ecx
|
||||
add eax,170
|
||||
mov px,eax
|
||||
mov eax,y
|
||||
sub eax,24
|
||||
imul eax,ebx
|
||||
cdq
|
||||
idiv ecx
|
||||
add eax,24
|
||||
mov py,eax
|
||||
invoke QueueTableHand3D,px,py,timeMs,0
|
||||
invoke DrawBJMiniCard3D,px,py,card,0
|
||||
ret
|
||||
DrawBJMiniFlight3D ENDP
|
||||
|
||||
RenderBJParty3D PROC uses ebx esi edi
|
||||
local guest:DWORD,stepX:DWORD,px:DWORD,pose:DWORD,shown:DWORD,slide:DWORD,cardId:DWORD,hide:DWORD
|
||||
call RenderCardTable3D
|
||||
cmp cbPartyRoom3D.pixels,0
|
||||
je @F
|
||||
mov esi,cbPartyRoom3D.pixels
|
||||
lea edi,screenBuffer
|
||||
mov ecx,SCREEN_SIZE
|
||||
rep movsd
|
||||
@@:
|
||||
invoke DrawBox,0,0,320,52,00151D20h
|
||||
invoke DrawString8x8,8,6,OFFSET cbTitle3D,00E8D7ADh
|
||||
invoke DrawString8x8,8,20,OFFSET cbDealerLabel3D,00D1B16Eh
|
||||
invoke DrawString8x8,192,20,OFFSET textBank3D,00A8DDB9h
|
||||
invoke FormatNumber,bankroll,OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,240,20,OFFSET hudNumBuffer,00F4F3E8h
|
||||
call DrawBJPartySelector3D
|
||||
xor edi,edi
|
||||
bj_party_render_guest:
|
||||
cmp edi,cbBotCount3D
|
||||
jae bj_party_render_dealer
|
||||
mov esi,edi
|
||||
imul esi,SIZEOF BJBot3D
|
||||
add esi,OFFSET cbBots3D
|
||||
mov guest,esi
|
||||
mov ebx,cbPartyX3D[edi*4]
|
||||
invoke DrawString8x8,ebx,54,cbPartyNames3D[edi*4],00E8D7ADh
|
||||
mov pose,edi
|
||||
cmp cbState3D,CB_BOTS
|
||||
jne @F
|
||||
cmp edi,cbBotTurn3D
|
||||
jne @F
|
||||
add pose,3
|
||||
@@:
|
||||
mov eax,ebx
|
||||
add eax,4
|
||||
shl eax,1
|
||||
invoke DrawAnimSprite3D,OFFSET cbPartyArt3D,pose,eax,112,144,144
|
||||
cmp cbState3D,CB_IDLE
|
||||
je bj_party_next_guest
|
||||
cmp cbState3D,CB_DEAL
|
||||
je @F
|
||||
invoke FormatNumber,[esi].BJBot3D.score,OFFSET hudNumBuffer
|
||||
lea eax,[ebx+64]
|
||||
invoke DrawString8x8,eax,54,OFFSET hudNumBuffer,00EDDFB1h
|
||||
@@:
|
||||
mov eax,[esi].BJBot3D.count
|
||||
mov shown,eax
|
||||
cmp cbState3D,CB_BOTS
|
||||
jne @F
|
||||
cmp edi,cbBotTurn3D
|
||||
jne @F
|
||||
cmp [esi].BJBot3D.state,BJ_BOT_FLIGHT
|
||||
jne @F
|
||||
inc shown
|
||||
inc eax
|
||||
@@:
|
||||
mov stepX,16
|
||||
cmp eax,4
|
||||
jbe @F
|
||||
dec eax
|
||||
mov ecx,eax
|
||||
mov eax,60
|
||||
xor edx,edx
|
||||
div ecx
|
||||
mov stepX,eax
|
||||
@@:
|
||||
xor ebx,ebx
|
||||
bj_party_guest_card:
|
||||
mov eax,ebx
|
||||
imul eax,stepX
|
||||
add eax,cbPartyX3D[edi*4]
|
||||
mov px,eax
|
||||
cmp ebx,[esi].BJBot3D.count
|
||||
jb bj_party_guest_existing
|
||||
invoke DrawBJMiniFlight3D,px,124,cbBotCard3D,cbBotTimer3D
|
||||
jmp bj_party_guest_next_card
|
||||
bj_party_guest_existing:
|
||||
mov edx,[esi+ebx*4].BJBot3D.cards
|
||||
mov cardId,edx
|
||||
cmp cbState3D,CB_DEAL
|
||||
jne bj_party_guest_fixed
|
||||
mov eax,cbBotCount3D
|
||||
add eax,2
|
||||
imul eax,ebx
|
||||
lea eax,[eax+edi+1]
|
||||
imul eax,TABLE_FLIGHT_MS
|
||||
mov ecx,cbTimer3D
|
||||
sub ecx,eax
|
||||
js bj_party_guest_next_card
|
||||
invoke DrawBJMiniFlight3D,px,124,cardId,ecx
|
||||
jmp bj_party_guest_next_card
|
||||
bj_party_guest_fixed:
|
||||
invoke DrawBJMiniCard3D,px,124,cardId,0
|
||||
bj_party_guest_next_card:
|
||||
inc ebx
|
||||
cmp ebx,shown
|
||||
jb bj_party_guest_card
|
||||
mov ecx,OFFSET cbBotWaitText3D
|
||||
cmp cbState3D,CB_RESULT
|
||||
jne bj_party_guest_live_status
|
||||
mov eax,[esi].BJBot3D.outcome
|
||||
mov ecx,cbBotResults3D[eax*4]
|
||||
jmp bj_party_guest_status
|
||||
bj_party_guest_live_status:
|
||||
cmp [esi].BJBot3D.state,BJ_BOT_DONE
|
||||
jne @F
|
||||
mov ecx,OFFSET cbBotStandText3D
|
||||
@@:
|
||||
cmp [esi].BJBot3D.score,21
|
||||
jbe @F
|
||||
mov ecx,OFFSET cbBotBustText3D
|
||||
@@:
|
||||
cmp cbState3D,CB_BOTS
|
||||
jne bj_party_guest_status
|
||||
cmp edi,cbBotTurn3D
|
||||
jne bj_party_guest_status
|
||||
mov ecx,OFFSET cbBotHitText3D
|
||||
bj_party_guest_status:
|
||||
mov eax,cbPartyX3D[edi*4]
|
||||
invoke DrawString8x8,eax,158,ecx,00DCE7DBh
|
||||
bj_party_next_guest:
|
||||
inc edi
|
||||
jmp bj_party_render_guest
|
||||
bj_party_render_dealer:
|
||||
cmp cbState3D,CB_IDLE
|
||||
je bj_party_render_controls
|
||||
mov stepX,22
|
||||
cmp cbDealerCount3D,5
|
||||
jbe @F
|
||||
mov eax,cbDealerCount3D
|
||||
dec eax
|
||||
mov ecx,eax
|
||||
mov eax,100
|
||||
xor edx,edx
|
||||
div ecx
|
||||
mov stepX,eax
|
||||
@@:
|
||||
xor ebx,ebx
|
||||
bj_party_dealer_card:
|
||||
mov eax,ebx
|
||||
imul eax,stepX
|
||||
add eax,64
|
||||
mov px,eax
|
||||
mov edx,cbDealer3D[ebx*4]
|
||||
mov cardId,edx
|
||||
mov hide,0
|
||||
cmp ebx,1
|
||||
jne @F
|
||||
cmp cbVisible3D,0
|
||||
jne @F
|
||||
mov hide,1
|
||||
@@:
|
||||
cmp cbState3D,CB_DEAL
|
||||
jne bj_party_dealer_fixed
|
||||
mov eax,cbBotCount3D
|
||||
add eax,2
|
||||
imul eax,ebx
|
||||
add eax,cbBotCount3D
|
||||
inc eax
|
||||
imul eax,TABLE_FLIGHT_MS
|
||||
mov ecx,cbTimer3D
|
||||
sub ecx,eax
|
||||
js bj_party_dealer_next
|
||||
; Initial dealer cards stay inside the header, with the hole card hidden.
|
||||
bj_party_dealer_fixed:
|
||||
invoke DrawBJMiniCard3D,px,20,cardId,hide
|
||||
bj_party_dealer_next:
|
||||
inc ebx
|
||||
cmp ebx,cbDealerCount3D
|
||||
jb bj_party_dealer_card
|
||||
xor ebx,ebx
|
||||
mov shown,0
|
||||
cmp cbState3D,CB_HIT
|
||||
jne @F
|
||||
mov shown,1
|
||||
@@:
|
||||
mov eax,cbPlayerCount3D
|
||||
add shown,eax
|
||||
mov stepX,40
|
||||
cmp shown,4
|
||||
jbe @F
|
||||
mov eax,shown
|
||||
dec eax
|
||||
mov ecx,eax
|
||||
mov eax,126
|
||||
xor edx,edx
|
||||
div ecx
|
||||
mov stepX,eax
|
||||
@@:
|
||||
mov eax,shown
|
||||
dec eax
|
||||
imul eax,stepX
|
||||
add eax,34
|
||||
mov edx,320
|
||||
sub edx,eax
|
||||
shr edx,1
|
||||
mov slide,edx
|
||||
bj_party_player_card:
|
||||
mov eax,ebx
|
||||
imul eax,stepX
|
||||
add eax,slide
|
||||
mov px,eax
|
||||
cmp ebx,cbPlayerCount3D
|
||||
jb bj_party_player_existing
|
||||
invoke DrawSlidingCard3D,px,168,cbCard3D,0,cbTimer3D
|
||||
jmp bj_party_player_next
|
||||
bj_party_player_existing:
|
||||
mov edx,cbPlayer3D[ebx*4]
|
||||
mov cardId,edx
|
||||
cmp cbState3D,CB_DEAL
|
||||
jne bj_party_player_fixed
|
||||
mov eax,cbBotCount3D
|
||||
add eax,2
|
||||
imul eax,ebx
|
||||
imul eax,TABLE_FLIGHT_MS
|
||||
mov ecx,cbTimer3D
|
||||
sub ecx,eax
|
||||
js bj_party_player_next
|
||||
invoke DrawSlidingCard3D,px,168,cardId,0,ecx
|
||||
jmp bj_party_player_next
|
||||
bj_party_player_fixed:
|
||||
invoke DrawNativeCard3D,px,168,cardId,0,34
|
||||
bj_party_player_next:
|
||||
inc ebx
|
||||
cmp ebx,shown
|
||||
jb bj_party_player_card
|
||||
invoke DrawString8x8,64,174,OFFSET cbPartyPlayerText3D,00E8D7ADh
|
||||
invoke FormatNumber,cbPlayerScore3D,OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,64,188,OFFSET hudNumBuffer,00EDDFB1h
|
||||
bj_party_render_controls:
|
||||
call DrawQueuedTableHand3D
|
||||
; UI labels stay above animated hands instead of disappearing during a deal.
|
||||
invoke DrawBox,0,52,320,10,00151D20h
|
||||
xor edi,edi
|
||||
bj_party_final_names:
|
||||
cmp edi,cbBotCount3D
|
||||
jae bj_party_final_names_done
|
||||
mov ebx,cbPartyX3D[edi*4]
|
||||
invoke DrawString8x8,ebx,54,cbPartyNames3D[edi*4],00E8D7ADh
|
||||
cmp cbState3D,CB_IDLE
|
||||
je bj_party_final_name_next
|
||||
cmp cbState3D,CB_DEAL
|
||||
je bj_party_final_name_next
|
||||
mov esi,edi
|
||||
imul esi,SIZEOF BJBot3D
|
||||
add esi,OFFSET cbBots3D
|
||||
invoke FormatNumber,[esi].BJBot3D.score,OFFSET hudNumBuffer
|
||||
lea eax,[ebx+64]
|
||||
invoke DrawString8x8,eax,54,OFFSET hudNumBuffer,00EDDFB1h
|
||||
bj_party_final_name_next:
|
||||
inc edi
|
||||
jmp bj_party_final_names
|
||||
bj_party_final_names_done:
|
||||
invoke DrawString8x8,8,174,OFFSET textBet3D,00DDCFB1h
|
||||
invoke FormatNumber,cbBet3D,OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,8,186,OFFSET hudNumBuffer,00F6F4DDh
|
||||
xor edi,edi
|
||||
cmp cbState3D,CB_IDLE
|
||||
je bj_party_ready
|
||||
cmp cbState3D,CB_RESULT
|
||||
je bj_party_ready
|
||||
invoke DrawStakeControls3D,0
|
||||
cmp cbState3D,CB_PLAYER
|
||||
jne @F
|
||||
mov edi,1
|
||||
@@:
|
||||
invoke DrawTableButton3D,8,OFFSET cbHitText3D,edi
|
||||
invoke DrawTableButton3D,86,OFFSET cbStandText3D,edi
|
||||
cmp cbPlayerCount3D,2
|
||||
jne bj_party_no_double
|
||||
mov eax,cbStake3D
|
||||
cmp bankroll,eax
|
||||
jae @F
|
||||
bj_party_no_double:
|
||||
xor edi,edi
|
||||
@@:
|
||||
invoke DrawTableButton3D,164,OFFSET cbDoubleText3D,edi
|
||||
jmp bj_party_render_exit
|
||||
bj_party_ready:
|
||||
invoke DrawStakeControls3D,1
|
||||
invoke DrawTableButton3D,125,OFFSET pkDealText3D,1
|
||||
cmp cbState3D,CB_RESULT
|
||||
jne bj_party_render_exit
|
||||
mov eax,cbOutcome3D
|
||||
mov ecx,OFFSET cbNaturalText3D
|
||||
cmp eax,3
|
||||
je @F
|
||||
mov ecx,cbResults3D[eax*4]
|
||||
@@:
|
||||
invoke DrawString8x8,8,226,ecx,00EFD583h
|
||||
bj_party_render_exit:
|
||||
cmp cbError3D,0
|
||||
je @F
|
||||
invoke DrawString8x8,80,183,OFFSET textNoCash3D,00F89880h
|
||||
@@:
|
||||
call RenderCardExit3D
|
||||
ret
|
||||
RenderBJParty3D ENDP
|
||||
685
src_graphics/native_clover.inc
Normal file
|
|
@ -0,0 +1,685 @@
|
|||
FreeNativeClover3D PROC
|
||||
invoke FreeAnimPack3D,OFFSET clpCabinet3D
|
||||
invoke FreeAnimPack3D,OFFSET clpSymbols3D
|
||||
ret
|
||||
FreeNativeClover3D ENDP
|
||||
|
||||
InitNativeClover3D PROC
|
||||
invoke LoadAnimPack3D,OFFSET clpCabinet3D,OFFSET clpCabinetPath3D
|
||||
test eax,eax
|
||||
jz clp_init_fail
|
||||
cmp clpCabinet3D.imageWidth,640
|
||||
jne clp_init_fail
|
||||
cmp clpCabinet3D.height,480
|
||||
jne clp_init_fail
|
||||
cmp clpCabinet3D.frames,1
|
||||
jne clp_init_fail
|
||||
invoke LoadAnimPack3D,OFFSET clpSymbols3D,OFFSET clpSymbolsPath3D
|
||||
test eax,eax
|
||||
jz clp_init_fail
|
||||
cmp clpSymbols3D.imageWidth,CLP_CELL
|
||||
jne clp_init_fail
|
||||
cmp clpSymbols3D.height,CLP_CELL
|
||||
jne clp_init_fail
|
||||
cmp clpSymbols3D.frames,7
|
||||
jne clp_init_fail
|
||||
mov clpState3D,SLOT_READY
|
||||
mov clpTimer3D,0
|
||||
mov clpStake3D,0
|
||||
mov clpGross3D,0
|
||||
mov clpTotal3D,0
|
||||
mov clpCount3D,0
|
||||
mov clpWinMask3D,0
|
||||
mov clpSelected3D,0
|
||||
mov clpPaytable3D,0
|
||||
mov clpLeave3D,0
|
||||
mov clpError3D,0
|
||||
mov clpBet3D,50
|
||||
mov clpBetIndex3D,1
|
||||
mov paused3D,0
|
||||
mov cardExitActive3D,0
|
||||
call ClearKeys3D
|
||||
mov eax,1
|
||||
ret
|
||||
clp_init_fail:
|
||||
call FreeNativeClover3D
|
||||
xor eax,eax
|
||||
ret
|
||||
InitNativeClover3D ENDP
|
||||
|
||||
; Tape contents and final board are frozen at the single stake debit.
|
||||
StartNativeClover3D PROC uses ebx esi edi
|
||||
cmp clpState3D,SLOT_SPIN
|
||||
je clp_start_done
|
||||
cmp clpPaytable3D,0
|
||||
jne clp_start_done
|
||||
cmp clpCabinet3D.pixels,0
|
||||
je clp_start_done
|
||||
cmp clpSymbols3D.pixels,0
|
||||
je clp_start_done
|
||||
mov eax,clpBet3D
|
||||
test eax,eax
|
||||
jz clp_start_done
|
||||
cmp eax,10000
|
||||
ja clp_start_done
|
||||
cmp eax,bankroll
|
||||
ja clp_start_money
|
||||
sub bankroll,eax
|
||||
mov clpStake3D,eax
|
||||
mov clpState3D,SLOT_SPIN
|
||||
mov clpTimer3D,0
|
||||
mov clpGross3D,0
|
||||
mov clpCount3D,0
|
||||
mov clpTotal3D,0
|
||||
mov clpWinMask3D,0
|
||||
mov clpSelected3D,0
|
||||
mov clpLeave3D,0
|
||||
mov clpError3D,0
|
||||
xor esi,esi
|
||||
clp_start_column:
|
||||
mov ebx,esi
|
||||
shl ebx,8
|
||||
xor edi,edi
|
||||
clp_start_tape:
|
||||
invoke RandomRange3D,7
|
||||
mov clpTape3D[ebx+edi*4],eax
|
||||
inc edi
|
||||
cmp edi,64
|
||||
jb clp_start_tape
|
||||
xor edi,edi
|
||||
clp_start_rows:
|
||||
mov ecx,edi
|
||||
imul ecx,5
|
||||
add ecx,esi
|
||||
mov eax,clpGrid3D[ecx*4]
|
||||
mov clpTape3D[ebx+edi*4],eax
|
||||
invoke RandomRange3D,7
|
||||
mov clpGrid3D[ecx*4],eax
|
||||
mov edx,clpSteps3D[esi*4]
|
||||
add edx,edi
|
||||
mov clpTape3D[ebx+edx*4],eax
|
||||
inc edi
|
||||
cmp edi,3
|
||||
jb clp_start_rows
|
||||
inc esi
|
||||
cmp esi,5
|
||||
jb clp_start_column
|
||||
call SaveProgress3D
|
||||
invoke PlayCasinoSound3D,OFFSET soundSlotSpin,0,1
|
||||
clp_start_done:
|
||||
ret
|
||||
clp_start_money:
|
||||
mov clpError3D,1
|
||||
ret
|
||||
StartNativeClover3D ENDP
|
||||
|
||||
; Reuse the original pure assembly evaluator, never the console game or payer.
|
||||
CloverEvaluate3D PROC uses ebx esi edi
|
||||
mov clpTotal3D,0
|
||||
mov clpCount3D,0
|
||||
mov clpWinMask3D,0
|
||||
mov clpJackpot3D,0
|
||||
xor esi,esi
|
||||
clp_eval_validate:
|
||||
cmp clpGrid3D[esi*4],6
|
||||
ja clp_eval_done
|
||||
inc esi
|
||||
cmp esi,15
|
||||
jb clp_eval_validate
|
||||
lea esi,clpGrid3D
|
||||
lea edi,slotGrid
|
||||
mov ecx,15
|
||||
rep movsd
|
||||
call EvaluateSlotCombos
|
||||
mov eax,slotBestMultiplier
|
||||
mov clpTotal3D,eax
|
||||
mov eax,slotWinMask
|
||||
mov clpWinMask3D,eax
|
||||
mov eax,slotJackpotHit
|
||||
mov clpJackpot3D,eax
|
||||
mov eax,slotComboCount
|
||||
mov clpCount3D,eax
|
||||
lea esi,slotComboNames
|
||||
lea edi,clpNames3D
|
||||
mov ecx,eax
|
||||
rep movsd
|
||||
lea esi,slotComboMults
|
||||
lea edi,clpMults3D
|
||||
mov ecx,clpCount3D
|
||||
rep movsd
|
||||
lea esi,slotComboMasks
|
||||
lea edi,clpMasks3D
|
||||
mov ecx,clpCount3D
|
||||
rep movsd
|
||||
clp_eval_done:
|
||||
xor eax,eax
|
||||
ret
|
||||
CloverEvaluate3D ENDP
|
||||
|
||||
SettleNativeClover3D PROC
|
||||
cmp clpState3D,SLOT_SPIN
|
||||
jne clp_settle_done
|
||||
call CloverEvaluate3D
|
||||
mov eax,clpTotal3D
|
||||
mul clpStake3D
|
||||
mov ecx,1000000000
|
||||
sub ecx,bankroll
|
||||
cmp eax,ecx
|
||||
jbe @F
|
||||
mov eax,ecx
|
||||
@@:
|
||||
mov clpGross3D,eax
|
||||
add bankroll,eax
|
||||
mov clpState3D,SLOT_RESULT
|
||||
mov clpTimer3D,3400
|
||||
xor eax,eax
|
||||
mov ecx,clpGross3D
|
||||
cmp ecx,clpStake3D
|
||||
seta al
|
||||
invoke NpcRecordRound3D,4,eax
|
||||
call SaveProgress3D
|
||||
mov eax,clpGross3D
|
||||
cmp eax,clpStake3D
|
||||
jb clp_settle_loss
|
||||
jne @F
|
||||
invoke PlayCasinoSound3D,0,0,0
|
||||
jmp clp_settle_leave
|
||||
@@:
|
||||
invoke PlayCasinoSound3D,OFFSET soundRoundWin,0,1
|
||||
jmp clp_settle_leave
|
||||
clp_settle_loss:
|
||||
invoke PlayCasinoSound3D,OFFSET soundRoundLose,0,1
|
||||
clp_settle_leave:
|
||||
cmp clpLeave3D,0
|
||||
je clp_settle_done
|
||||
call CloverEscape3D
|
||||
clp_settle_done:
|
||||
ret
|
||||
SettleNativeClover3D ENDP
|
||||
|
||||
CloverEscape3D PROC
|
||||
mov paused3D,0
|
||||
cmp clpPaytable3D,0
|
||||
je @F
|
||||
mov clpPaytable3D,0
|
||||
call ClearKeys3D
|
||||
ret
|
||||
@@:
|
||||
cmp clpState3D,SLOT_SPIN
|
||||
jne clp_escape_hall
|
||||
mov clpLeave3D,1
|
||||
call ClearKeys3D
|
||||
ret
|
||||
clp_escape_hall:
|
||||
mov clpLeave3D,0
|
||||
mov engineMode,MODE_WALK
|
||||
call ClearKeys3D
|
||||
invoke PlayCasinoSound3D,0,0,0
|
||||
ret
|
||||
CloverEscape3D ENDP
|
||||
|
||||
CloverReelPosition3D PROC uses ebx index:DWORD
|
||||
mov ebx,index
|
||||
xor eax,eax
|
||||
cmp ebx,4
|
||||
ja clp_pos_done
|
||||
cmp clpState3D,SLOT_SPIN
|
||||
jne clp_pos_end
|
||||
mov eax,clpTimer3D
|
||||
cmp eax,clpDurations3D[ebx*4]
|
||||
jae clp_pos_end
|
||||
shl eax,10
|
||||
xor edx,edx
|
||||
div clpDurations3D[ebx*4]
|
||||
mov ecx,2048
|
||||
sub ecx,eax
|
||||
imul eax,ecx
|
||||
mov ecx,clpSteps3D[ebx*4]
|
||||
imul ecx,CLP_CELL
|
||||
mul ecx
|
||||
shrd eax,edx,20
|
||||
ret
|
||||
clp_pos_end:
|
||||
mov eax,clpSteps3D[ebx*4]
|
||||
imul eax,CLP_CELL
|
||||
clp_pos_done:
|
||||
ret
|
||||
CloverReelPosition3D ENDP
|
||||
|
||||
HandleNativeClover3D PROC uses ebx
|
||||
cmp mouseClick3D,0
|
||||
je clp_handle_tick
|
||||
mov mouseClick3D,0
|
||||
mov eax,mouseY3D
|
||||
cmp eax,3
|
||||
jb clp_handle_tick
|
||||
cmp eax,17
|
||||
jae clp_handle_mouse_controls
|
||||
cmp mouseX3D,252
|
||||
jb clp_handle_tick
|
||||
cmp mouseX3D,312
|
||||
jae clp_handle_tick
|
||||
call CloverEscape3D
|
||||
cmp clpState3D,SLOT_SPIN
|
||||
je clp_handle_tick
|
||||
ret
|
||||
clp_handle_mouse_controls:
|
||||
cmp clpState3D,SLOT_SPIN
|
||||
je clp_handle_tick
|
||||
cmp clpPaytable3D,0
|
||||
je @F
|
||||
cmp eax,202
|
||||
jb clp_handle_tick
|
||||
cmp eax,220
|
||||
jae clp_handle_tick
|
||||
cmp mouseX3D,112
|
||||
jb clp_handle_tick
|
||||
cmp mouseX3D,208
|
||||
jae clp_handle_tick
|
||||
mov clpPaytable3D,0
|
||||
ret
|
||||
@@:
|
||||
cmp eax,170
|
||||
jb clp_handle_tick
|
||||
cmp eax,185
|
||||
jae clp_handle_mouse_footer
|
||||
cmp mouseX3D,232
|
||||
jb clp_handle_tick
|
||||
cmp mouseX3D,250
|
||||
jb clp_handle_previous
|
||||
cmp mouseX3D,292
|
||||
jb clp_handle_tick
|
||||
cmp mouseX3D,310
|
||||
jb clp_handle_next
|
||||
jmp clp_handle_tick
|
||||
clp_handle_mouse_footer:
|
||||
cmp eax,222
|
||||
jb clp_handle_tick
|
||||
cmp eax,238
|
||||
jae clp_handle_tick
|
||||
mov eax,mouseX3D
|
||||
cmp eax,11
|
||||
jb clp_handle_tick
|
||||
cmp eax,29
|
||||
jb clp_handle_down
|
||||
cmp eax,35
|
||||
jb clp_handle_tick
|
||||
cmp eax,53
|
||||
jb clp_handle_up
|
||||
cmp eax,120
|
||||
jb clp_handle_tick
|
||||
cmp eax,190
|
||||
jb clp_handle_start
|
||||
cmp eax,202
|
||||
jb clp_handle_tick
|
||||
cmp eax,272
|
||||
jb clp_handle_paytable
|
||||
clp_handle_tick:
|
||||
cmp clpState3D,SLOT_SPIN
|
||||
jne clp_handle_keys
|
||||
mov eax,deltaTime3D
|
||||
cmp eax,250
|
||||
jbe @F
|
||||
mov eax,250
|
||||
@@:
|
||||
add clpTimer3D,eax
|
||||
cmp clpTimer3D,3400
|
||||
jb clp_handle_done
|
||||
call SettleNativeClover3D
|
||||
ret
|
||||
clp_handle_keys:
|
||||
invoke Pressed3D,50h
|
||||
test eax,eax
|
||||
jnz clp_handle_paytable
|
||||
cmp clpPaytable3D,0
|
||||
je clp_handle_game_keys
|
||||
invoke Pressed3D,20h
|
||||
test eax,eax
|
||||
jnz clp_handle_paytable
|
||||
invoke Pressed3D,0Dh
|
||||
test eax,eax
|
||||
jnz clp_handle_paytable
|
||||
ret
|
||||
clp_handle_game_keys:
|
||||
invoke Pressed3D,25h
|
||||
test eax,eax
|
||||
jnz clp_handle_previous
|
||||
invoke Pressed3D,27h
|
||||
test eax,eax
|
||||
jnz clp_handle_next
|
||||
invoke Pressed3D,57h
|
||||
test eax,eax
|
||||
jnz clp_handle_up
|
||||
invoke Pressed3D,26h
|
||||
test eax,eax
|
||||
jnz clp_handle_up
|
||||
invoke Pressed3D,53h
|
||||
test eax,eax
|
||||
jnz clp_handle_down
|
||||
invoke Pressed3D,28h
|
||||
test eax,eax
|
||||
jnz clp_handle_down
|
||||
invoke Pressed3D,20h
|
||||
test eax,eax
|
||||
jnz clp_handle_start
|
||||
invoke Pressed3D,0Dh
|
||||
test eax,eax
|
||||
jz clp_handle_done
|
||||
clp_handle_start:
|
||||
call StartNativeClover3D
|
||||
ret
|
||||
clp_handle_paytable:
|
||||
xor clpPaytable3D,1
|
||||
ret
|
||||
clp_handle_previous:
|
||||
cmp clpCount3D,0
|
||||
je clp_handle_done
|
||||
cmp clpSelected3D,0
|
||||
jne @F
|
||||
mov eax,clpCount3D
|
||||
mov clpSelected3D,eax
|
||||
@@:
|
||||
dec clpSelected3D
|
||||
ret
|
||||
clp_handle_next:
|
||||
cmp clpCount3D,0
|
||||
je clp_handle_done
|
||||
inc clpSelected3D
|
||||
mov eax,clpSelected3D
|
||||
cmp eax,clpCount3D
|
||||
jb clp_handle_done
|
||||
mov clpSelected3D,0
|
||||
ret
|
||||
clp_handle_up:
|
||||
cmp clpBetIndex3D,6
|
||||
jae clp_handle_done
|
||||
inc clpBetIndex3D
|
||||
jmp clp_handle_bet
|
||||
clp_handle_down:
|
||||
cmp clpBetIndex3D,0
|
||||
je clp_handle_done
|
||||
dec clpBetIndex3D
|
||||
clp_handle_bet:
|
||||
mov ecx,clpBetIndex3D
|
||||
mov eax,slotBetValues3D[ecx*4]
|
||||
mov clpBet3D,eax
|
||||
mov clpError3D,0
|
||||
clp_handle_done:
|
||||
ret
|
||||
HandleNativeClover3D ENDP
|
||||
|
||||
DrawCloverSymbol3D PROC uses ebx esi edi symbol:DWORD,x:DWORD,y:DWORD
|
||||
local row:DWORD,lastRow:DWORD,source:DWORD
|
||||
cmp symbol,6
|
||||
ja clp_symbol_done
|
||||
mov eax,clpSymbols3D.pixels
|
||||
test eax,eax
|
||||
jz clp_symbol_done
|
||||
mov ecx,symbol
|
||||
imul ecx,CLP_CELL*CLP_CELL*4
|
||||
add eax,ecx
|
||||
mov source,eax
|
||||
mov eax,y
|
||||
cmp eax,CLP_TOP
|
||||
jge @F
|
||||
mov eax,CLP_TOP
|
||||
@@:
|
||||
mov row,eax
|
||||
mov eax,y
|
||||
add eax,CLP_CELL
|
||||
cmp eax,CLP_BOTTOM
|
||||
jle @F
|
||||
mov eax,CLP_BOTTOM
|
||||
@@:
|
||||
mov lastRow,eax
|
||||
clp_symbol_row:
|
||||
mov eax,row
|
||||
cmp eax,lastRow
|
||||
jge clp_symbol_done
|
||||
mov ecx,eax
|
||||
sub ecx,y
|
||||
imul ecx,CLP_CELL*4
|
||||
mov esi,source
|
||||
add esi,ecx
|
||||
imul eax,640*4
|
||||
mov ecx,x
|
||||
lea edi,screenBuffer[eax+ecx*4]
|
||||
mov ecx,CLP_CELL
|
||||
clp_symbol_column:
|
||||
lodsd
|
||||
test eax,0FF000000h
|
||||
jz @F
|
||||
and eax,00FFFFFFh
|
||||
mov [edi],eax
|
||||
@@:
|
||||
add edi,4
|
||||
dec ecx
|
||||
jnz clp_symbol_column
|
||||
inc row
|
||||
jmp clp_symbol_row
|
||||
clp_symbol_done:
|
||||
ret
|
||||
DrawCloverSymbol3D ENDP
|
||||
|
||||
DrawCloverReel3D PROC uses ebx esi edi index:DWORD
|
||||
local symbolY:DWORD,baseStop:DWORD,columnX:DWORD
|
||||
mov ebx,index
|
||||
mov eax,clpColumns3D[ebx*4]
|
||||
mov columnX,eax
|
||||
cmp clpState3D,SLOT_SPIN
|
||||
jne clp_reel_static
|
||||
invoke CloverReelPosition3D,ebx
|
||||
xor edx,edx
|
||||
mov ecx,CLP_CELL
|
||||
div ecx
|
||||
mov baseStop,eax
|
||||
mov eax,CLP_TOP
|
||||
sub eax,edx
|
||||
mov symbolY,eax
|
||||
shl ebx,8
|
||||
xor esi,esi
|
||||
clp_reel_tape:
|
||||
mov ecx,baseStop
|
||||
add ecx,esi
|
||||
mov eax,clpTape3D[ebx+ecx*4]
|
||||
invoke DrawCloverSymbol3D,eax,columnX,symbolY
|
||||
add symbolY,CLP_CELL
|
||||
inc esi
|
||||
cmp esi,4
|
||||
jb clp_reel_tape
|
||||
ret
|
||||
clp_reel_static:
|
||||
mov symbolY,CLP_TOP
|
||||
xor esi,esi
|
||||
clp_reel_rows:
|
||||
mov ecx,esi
|
||||
imul ecx,5
|
||||
add ecx,ebx
|
||||
mov eax,clpGrid3D[ecx*4]
|
||||
invoke DrawCloverSymbol3D,eax,columnX,symbolY
|
||||
add symbolY,CLP_CELL
|
||||
inc esi
|
||||
cmp esi,3
|
||||
jb clp_reel_rows
|
||||
ret
|
||||
DrawCloverReel3D ENDP
|
||||
|
||||
CloverComboText3D PROC index:DWORD
|
||||
mov ecx,index
|
||||
cmp ecx,clpCount3D
|
||||
jae clp_combo_none
|
||||
mov edx,clpNames3D[ecx*4]
|
||||
xor ecx,ecx
|
||||
clp_combo_lookup:
|
||||
cmp edx,clpLegacyNames3D[ecx*4]
|
||||
je clp_combo_found
|
||||
inc ecx
|
||||
cmp ecx,11
|
||||
jb clp_combo_lookup
|
||||
clp_combo_none:
|
||||
mov eax,OFFSET clpNoCombo3D
|
||||
ret
|
||||
clp_combo_found:
|
||||
mov eax,clpShapeNames3D[ecx*4]
|
||||
ret
|
||||
CloverComboText3D ENDP
|
||||
|
||||
RenderNativeClover3D PROC uses ebx esi edi
|
||||
local cellX:DWORD,cellY:DWORD,selectedMask:DWORD
|
||||
mov esi,clpCabinet3D.pixels
|
||||
test esi,esi
|
||||
jz clp_render_done
|
||||
lea edi,screenBuffer
|
||||
mov ecx,SCREEN_SIZE
|
||||
rep movsd
|
||||
xor esi,esi
|
||||
clp_render_reels:
|
||||
mov ebx,clpColumns3D[esi*4]
|
||||
shr ebx,1
|
||||
invoke DrawBoxBorder,ebx,63,28,84,000D1816h,00405A46h,1
|
||||
invoke DrawCloverReel3D,esi
|
||||
inc esi
|
||||
cmp esi,5
|
||||
jb clp_render_reels
|
||||
cmp clpState3D,SLOT_RESULT
|
||||
jne clp_render_header
|
||||
mov ecx,clpSelected3D
|
||||
cmp ecx,clpCount3D
|
||||
jae clp_render_header
|
||||
mov eax,clpMasks3D[ecx*4]
|
||||
mov selectedMask,eax
|
||||
xor esi,esi
|
||||
clp_render_highlight:
|
||||
mov eax,1
|
||||
mov ecx,esi
|
||||
shl eax,cl
|
||||
test selectedMask,eax
|
||||
jz clp_render_next_cell
|
||||
mov eax,esi
|
||||
xor edx,edx
|
||||
mov ecx,5
|
||||
div ecx
|
||||
imul eax,28
|
||||
add eax,63
|
||||
mov cellY,eax
|
||||
mov ebx,clpColumns3D[edx*4]
|
||||
shr ebx,1
|
||||
mov cellX,ebx
|
||||
; Border strips do not paint over the transparent symbol interior.
|
||||
invoke DrawBox,ebx,cellY,28,1,00E9CE71h
|
||||
mov eax,cellY
|
||||
add eax,27
|
||||
invoke DrawBox,ebx,eax,28,1,00E9CE71h
|
||||
invoke DrawBox,ebx,cellY,1,28,00E9CE71h
|
||||
add ebx,27
|
||||
invoke DrawBox,ebx,cellY,1,28,00E9CE71h
|
||||
clp_render_next_cell:
|
||||
inc esi
|
||||
cmp esi,15
|
||||
jb clp_render_highlight
|
||||
clp_render_header:
|
||||
invoke DrawBox,0,0,320,19,00151D20h
|
||||
invoke DrawString8x8,8,6,OFFSET clpTitle3D,00E8D7ADh
|
||||
invoke DrawString8x8,108,6,OFFSET textBank3D,00A8DDB9h
|
||||
invoke FormatNumber,bankroll,OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,157,6,OFFSET hudNumBuffer,00F4F3E8h
|
||||
invoke DrawBoxBorder,252,3,60,14,002C3637h,00687672h,1
|
||||
invoke DrawString8x8,258,6,OFFSET cardExitButton3D,00E9D8B0h
|
||||
invoke DrawBox,63,160,194,26,00151D20h
|
||||
mov ebx,OFFSET slotReadyText3D
|
||||
cmp clpState3D,SLOT_SPIN
|
||||
jne @F
|
||||
mov ebx,OFFSET slotRollingText3D
|
||||
@@:
|
||||
cmp clpState3D,SLOT_RESULT
|
||||
jne @F
|
||||
mov ebx,OFFSET clpNoCombo3D
|
||||
cmp clpCount3D,0
|
||||
je @F
|
||||
mov ebx,OFFSET clpTotalText3D
|
||||
@@:
|
||||
cmp clpError3D,0
|
||||
je @F
|
||||
mov ebx,OFFSET slotNoMoney3D
|
||||
@@:
|
||||
cmp clpLeave3D,0
|
||||
je @F
|
||||
mov ebx,OFFSET slotExitText3D
|
||||
@@:
|
||||
invoke DrawString8x8,72,163,ebx,00E8D7ADh
|
||||
cmp clpState3D,SLOT_RESULT
|
||||
jne clp_render_footer
|
||||
cmp clpCount3D,0
|
||||
je clp_render_footer
|
||||
invoke DrawString8x8,208,163,OFFSET strMultiplier3D,00A8DDB9h
|
||||
invoke FormatNumber,clpTotal3D,OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,216,163,OFFSET hudNumBuffer,00A8DDB9h
|
||||
invoke CloverComboText3D,clpSelected3D
|
||||
invoke DrawString8x8,72,175,eax,00F4F3E8h
|
||||
mov ecx,clpSelected3D
|
||||
invoke FormatNumber,clpMults3D[ecx*4],OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,208,175,OFFSET strMultiplier3D,00E9CE71h
|
||||
invoke DrawString8x8,216,175,OFFSET hudNumBuffer,00E9CE71h
|
||||
invoke DrawBoxBorder,232,170,18,15,0025372Ch,00E9CE71h,1
|
||||
invoke DrawBoxBorder,292,170,18,15,0025372Ch,00E9CE71h,1
|
||||
invoke DrawString8x8,237,174,OFFSET clpLeft3D,00E9CE71h
|
||||
invoke DrawString8x8,297,174,OFFSET clpRight3D,00E9CE71h
|
||||
mov eax,clpSelected3D
|
||||
inc eax
|
||||
invoke FormatNumber,eax,OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,252,174,OFFSET hudNumBuffer,00F4F3E8h
|
||||
invoke DrawString8x8,268,174,OFFSET clpSlash3D,00F4F3E8h
|
||||
invoke FormatNumber,clpCount3D,OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,276,174,OFFSET hudNumBuffer,00F4F3E8h
|
||||
clp_render_footer:
|
||||
invoke DrawBox,0,198,320,42,00151D20h
|
||||
invoke DrawString8x8,11,201,OFFSET slotBetText3D,00E8D7ADh
|
||||
invoke FormatNumber,clpBet3D,OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,75,201,OFFSET hudNumBuffer,00F4F3E8h
|
||||
cmp clpState3D,SLOT_RESULT
|
||||
jne @F
|
||||
invoke DrawSlotTotals3D,clpGross3D,clpStake3D,120
|
||||
@@:
|
||||
mov ebx,1
|
||||
cmp clpState3D,SLOT_SPIN
|
||||
jne @F
|
||||
xor ebx,ebx
|
||||
@@:
|
||||
invoke DrawBoxBorder,11,222,18,16,0025372Ch,00EEE5CDh,1
|
||||
invoke DrawBoxBorder,35,222,18,16,0025372Ch,00EEE5CDh,1
|
||||
invoke DrawString8x8,16,226,OFFSET tableMinusText3D,00EEE5CDh
|
||||
invoke DrawString8x8,40,226,OFFSET tablePlusText3D,00EEE5CDh
|
||||
invoke DrawTableButton3D,120,OFFSET slotSpinText3D,ebx
|
||||
invoke DrawTableButton3D,202,OFFSET slotPayText3D,ebx
|
||||
cmp clpPaytable3D,0
|
||||
je clp_render_done
|
||||
invoke DrawBoxBorder,18,22,284,200,00151D20h,00D1B16Eh,1
|
||||
invoke DrawString8x8,76,29,OFFSET slotPayTitle3D,00E8D7ADh
|
||||
invoke DrawString8x8,28,44,OFFSET clpSymbolsText3D,00A8DDB9h
|
||||
invoke DrawString8x8,164,44,OFFSET clpShapesText3D,00A8DDB9h
|
||||
xor esi,esi
|
||||
clp_render_pay_row:
|
||||
mov edi,esi
|
||||
imul edi,11
|
||||
add edi,58
|
||||
mov eax,clpShapeNames3D[esi*4]
|
||||
invoke DrawString8x8,156,edi,eax,00F4F3E8h
|
||||
invoke FormatNumber,clpShapeFactors3D[esi*4],OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,280,edi,OFFSET hudNumBuffer,00E8D7ADh
|
||||
cmp esi,7
|
||||
jae clp_render_pay_next
|
||||
mov eax,clpSymbolNames3D[esi*4]
|
||||
invoke DrawString8x8,28,edi,eax,00F4F3E8h
|
||||
invoke FormatNumber,slotSymbolValues[esi*4],OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,132,edi,OFFSET hudNumBuffer,00E8D7ADh
|
||||
clp_render_pay_next:
|
||||
inc esi
|
||||
cmp esi,11
|
||||
jb clp_render_pay_row
|
||||
invoke DrawString8x8,28,181,OFFSET clpOverlapText3D,00A8DDB9h
|
||||
invoke DrawString8x8,28,193,OFFSET slotPayNote3D,00A8DDB9h
|
||||
invoke DrawBoxBorder,112,204,96,15,003B6C59h,00E9D8B0h,1
|
||||
invoke DrawString8x8,128,207,OFFSET slotCloseText3D,00E9D8B0h
|
||||
clp_render_done:
|
||||
ret
|
||||
RenderNativeClover3D ENDP
|
||||
80
src_graphics/native_clover_data.inc
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
MODE_CLOVER equ 21
|
||||
CLP_CELL equ 56
|
||||
CLP_TOP equ 126
|
||||
CLP_BOTTOM equ 294
|
||||
InitNativeClover3D PROTO
|
||||
FreeNativeClover3D PROTO
|
||||
StartNativeClover3D PROTO
|
||||
HandleNativeClover3D PROTO
|
||||
RenderNativeClover3D PROTO
|
||||
CloverEscape3D PROTO
|
||||
SettleNativeClover3D PROTO
|
||||
CloverEvaluate3D PROTO
|
||||
CloverReelPosition3D PROTO :DWORD
|
||||
DrawCloverSymbol3D PROTO :DWORD,:DWORD,:DWORD
|
||||
DrawCloverReel3D PROTO :DWORD
|
||||
CloverComboText3D PROTO :DWORD
|
||||
.data
|
||||
clpCabinet3D AnimPack3D <>
|
||||
clpSymbols3D AnimPack3D <>
|
||||
clpCabinetPath3D db "assets\animations\clover\cabinet-v1.bin",0
|
||||
clpSymbolsPath3D db "assets\animations\clover\symbols-v1.bin",0
|
||||
clpState3D dd 0
|
||||
clpTimer3D dd 0
|
||||
clpBet3D dd 50
|
||||
clpBetIndex3D dd 1
|
||||
clpStake3D dd 0
|
||||
clpGross3D dd 0
|
||||
clpTotal3D dd 0
|
||||
clpWinMask3D dd 0
|
||||
clpCount3D dd 0
|
||||
clpSelected3D dd 0
|
||||
clpJackpot3D dd 0
|
||||
clpPaytable3D dd 0
|
||||
clpLeave3D dd 0
|
||||
clpError3D dd 0
|
||||
clpGrid3D dd 0,1,2,3,4,5,6,0,1,2,3,4,5,6,0
|
||||
clpTape3D dd 320 dup(0)
|
||||
clpNames3D dd 32 dup(0)
|
||||
clpMults3D dd 32 dup(0)
|
||||
clpMasks3D dd 32 dup(0)
|
||||
clpDurations3D dd 1800,2200,2600,3000,3400
|
||||
clpSteps3D dd 28,32,36,40,44
|
||||
clpColumns3D dd 144,216,288,360,432
|
||||
clpTitle3D db 202,203,197,194,197,208,32,53,120,51,0
|
||||
clpTotalText3D db 204,205,206,198,200,210,197,203,220,0
|
||||
clpNoCombo3D db 205,197,210,32,202,206,204,193,200,205,192,214,200,201,0
|
||||
clpSymbolsText3D db 209,200,204,194,206,203,0
|
||||
clpShapesText3D db 212,200,195,211,208,192,0
|
||||
clpOverlapText3D db 212,200,195,211,208,192,32,120,32,209,200,204,194,206,203,59,32,209,211,204,204,192,0
|
||||
clpShape0 db 208,223,196,32,51,0
|
||||
clpShape1 db 208,223,196,32,52,0
|
||||
clpShape2 db 208,223,196,32,53,0
|
||||
clpShape3 db 194,197,208,210,200,202,192,203,220,0
|
||||
clpShape4 db 196,200,192,195,206,205,192,203,220,0
|
||||
clpShape5 db 209,210,208,197,203,202,192,32,194,194,197,208,213,0
|
||||
clpShape6 db 209,210,208,197,203,202,192,32,194,205,200,199,0
|
||||
clpShape7 db 194,197,208,213,205,200,201,32,208,223,196,0
|
||||
clpShape8 db 205,200,198,205,200,201,32,208,223,196,0
|
||||
clpShape9 db 195,203,192,199,0
|
||||
clpShape10 db 196,198,197,202,207,206,210,0
|
||||
clpSymbol0 db 202,203,197,194,197,208,0
|
||||
clpSymbol1 db 203,200,204,206,205,0
|
||||
clpSymbol2 db 194,200,216,205,223,0
|
||||
clpSymbol3 db 202,206,203,206,202,206,203,0
|
||||
clpSymbol4 db 192,203,204,192,199,0
|
||||
clpSymbol5 db 209,211,205,196,211,202,0
|
||||
clpSymbol6 db 209,197,204,220,0
|
||||
clpShapeNames3D dd OFFSET clpShape0,OFFSET clpShape1,OFFSET clpShape2
|
||||
dd OFFSET clpShape3,OFFSET clpShape4,OFFSET clpShape5,OFFSET clpShape6
|
||||
dd OFFSET clpShape7,OFFSET clpShape8,OFFSET clpShape9,OFFSET clpShape10
|
||||
clpLegacyNames3D dd OFFSET slotComboHorM,OFFSET slotComboHorL,OFFSET slotComboHorXL
|
||||
dd OFFSET slotComboVertM,OFFSET slotComboDiagM,OFFSET slotComboUp,OFFSET slotComboDown
|
||||
dd OFFSET slotComboSky,OFFSET slotComboEarth,OFFSET slotComboEye,OFFSET slotComboJackpot
|
||||
clpShapeFactors3D dd 1,2,3,1,1,4,4,7,7,8,10
|
||||
clpSymbolNames3D dd OFFSET clpSymbol0,OFFSET clpSymbol1,OFFSET clpSymbol2,OFFSET clpSymbol3
|
||||
dd OFFSET clpSymbol4,OFFSET clpSymbol5,OFFSET clpSymbol6
|
||||
clpLeft3D db "<",0
|
||||
clpRight3D db ">",0
|
||||
clpSlash3D db "/",0
|
||||
.code
|
||||
|
|
@ -98,6 +98,10 @@ coin_settle_loss:
|
|||
invoke PlayCasinoSound3D,OFFSET soundLose,0,1
|
||||
coin_settle_save:
|
||||
mov coin3d_state,COIN_RESULT
|
||||
xor eax,eax
|
||||
cmp coin3d_win,0
|
||||
setne al
|
||||
invoke NpcRecordRound3D,0,eax
|
||||
call SaveProgress3D
|
||||
coin_settle_done:
|
||||
ret
|
||||
|
|
|
|||
|
|
@ -133,6 +133,10 @@ dk_settle_loss:
|
|||
invoke PlayCasinoSound3D, OFFSET soundRoundLose, 0, 1
|
||||
dk_settle_save:
|
||||
call ClearKeys3D
|
||||
xor eax,eax
|
||||
cmp dkOutcome3D,0
|
||||
sete al
|
||||
invoke NpcRecordRound3D,5,eax
|
||||
call SaveProgress3D
|
||||
dk_settle_done:
|
||||
ret
|
||||
|
|
|
|||
|
|
@ -265,6 +265,10 @@ poker_fold_player:
|
|||
poker_fold_settled:
|
||||
mov pkState3D, PK_RESULT
|
||||
call ClearKeys3D
|
||||
xor eax,eax
|
||||
cmp pkOutcome3D,0
|
||||
sete al
|
||||
invoke NpcRecordRound3D,2,eax
|
||||
call SaveProgress3D
|
||||
poker_fold_done:
|
||||
ret
|
||||
|
|
@ -362,6 +366,10 @@ poker_showdown_tie:
|
|||
poker_showdown_settled:
|
||||
mov pkState3D, PK_RESULT
|
||||
call ClearKeys3D
|
||||
xor eax,eax
|
||||
cmp pkOutcome3D,0
|
||||
sete al
|
||||
invoke NpcRecordRound3D,2,eax
|
||||
call SaveProgress3D
|
||||
poker_showdown_done:
|
||||
ret
|
||||
|
|
|
|||
|
|
@ -135,6 +135,12 @@ SettleNativeSlots3D PROC uses esi
|
|||
jne slot_settle_done
|
||||
invoke SlotMultiplier3D,slotReel1,slotReel2,slotReel3
|
||||
mul slotStake3D
|
||||
mov ecx,1000000000
|
||||
sub ecx,bankroll
|
||||
cmp eax,ecx
|
||||
jbe @F
|
||||
mov eax,ecx
|
||||
@@:
|
||||
mov slotWinAmount,eax
|
||||
add bankroll,eax
|
||||
jc slot_settle_cap
|
||||
|
|
@ -153,9 +159,19 @@ slot_settle_stops:
|
|||
mov slotSpinTimer,3000
|
||||
mov slotSpinState,SLOT_RESULT
|
||||
mov slotEffects3D,0
|
||||
xor eax,eax
|
||||
mov ecx,slotWinAmount
|
||||
cmp ecx,slotStake3D
|
||||
seta al
|
||||
invoke NpcRecordRound3D,4,eax
|
||||
call SaveProgress3D
|
||||
cmp slotWinAmount,0
|
||||
je slot_settle_loss
|
||||
mov eax,slotWinAmount
|
||||
cmp eax,slotStake3D
|
||||
jb slot_settle_loss
|
||||
jne @F
|
||||
invoke PlayCasinoSound3D,0,0,0
|
||||
jmp slot_settle_exit
|
||||
@@:
|
||||
invoke PlayCasinoSound3D,OFFSET soundRoundWin,0,1
|
||||
jmp slot_settle_exit
|
||||
slot_settle_loss:
|
||||
|
|
@ -476,8 +492,9 @@ slot_render_reels:
|
|||
invoke DrawBox,232,94,4,3,00E9CE71h
|
||||
cmp slotSpinState,SLOT_RESULT
|
||||
jne slot_render_header
|
||||
cmp slotWinAmount,0
|
||||
je slot_render_header
|
||||
mov eax,slotWinAmount
|
||||
cmp eax,slotStake3D
|
||||
jbe slot_render_header
|
||||
mov eax,slotEffects3D
|
||||
xor edx,edx
|
||||
mov ecx,200
|
||||
|
|
@ -501,7 +518,10 @@ slot_render_header:
|
|||
cmp slotSpinState,SLOT_RESULT
|
||||
jne @F
|
||||
mov ebx,OFFSET slotLoseText3D
|
||||
cmp slotWinAmount,0
|
||||
mov eax,slotWinAmount
|
||||
cmp eax,slotStake3D
|
||||
jb @F
|
||||
mov ebx,OFFSET slotRefundText3D
|
||||
je @F
|
||||
mov ebx,OFFSET slotWinText3D
|
||||
@@:
|
||||
|
|
@ -518,15 +538,22 @@ slot_render_header:
|
|||
invoke DrawString8x8,104,149,ebx,00E8D7ADh
|
||||
cmp slotSpinState,SLOT_RESULT
|
||||
jne slot_render_controls
|
||||
cmp slotWinAmount,0
|
||||
je slot_render_controls
|
||||
cmp ebx,OFFSET slotWinText3D
|
||||
je @F
|
||||
cmp ebx,OFFSET slotRefundText3D
|
||||
jne slot_render_controls
|
||||
@@:
|
||||
invoke FormatNumber,slotWinAmount,OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,164,149,OFFSET hudNumBuffer,00A8DDB9h
|
||||
slot_render_controls:
|
||||
invoke DrawBox,0,202,320,38,00151D20h
|
||||
invoke DrawString8x8,11,207,OFFSET slotBetText3D,00E8D7ADh
|
||||
invoke DrawBox,0,198,320,42,00151D20h
|
||||
invoke DrawString8x8,11,201,OFFSET slotBetText3D,00E8D7ADh
|
||||
invoke FormatNumber,slotBet,OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,83,207,OFFSET hudNumBuffer,00F4F3E8h
|
||||
invoke DrawString8x8,75,201,OFFSET hudNumBuffer,00F4F3E8h
|
||||
cmp slotSpinState,SLOT_RESULT
|
||||
jne @F
|
||||
invoke DrawSlotTotals3D,slotWinAmount,slotStake3D,120
|
||||
@@:
|
||||
mov ebx,1
|
||||
cmp slotSpinState,SLOT_SPIN
|
||||
jne @F
|
||||
|
|
@ -547,12 +574,12 @@ slot_render_controls:
|
|||
je slot_render_done
|
||||
invoke DrawBoxBorder,30,23,260,198,00151D20h,00D1B16Eh,1
|
||||
invoke DrawString8x8,76,31,OFFSET slotPayTitle3D,00E8D7ADh
|
||||
invoke DrawString8x8,66,48,OFFSET slotTripleText3D,00A8DDB9h
|
||||
invoke DrawString8x8,42,48,OFFSET slotTripleText3D,00A8DDB9h
|
||||
xor esi,esi
|
||||
slot_render_pay_row:
|
||||
mov edi,esi
|
||||
imul edi,14
|
||||
add edi,66
|
||||
imul edi,12
|
||||
add edi,62
|
||||
mov eax,slotSymbolNames3D[esi*4]
|
||||
invoke DrawString8x8,62,edi,eax,00F4F3E8h
|
||||
invoke FormatNumber,slotTriple3D[esi*4],OFFSET hudNumBuffer
|
||||
|
|
@ -561,10 +588,39 @@ slot_render_pay_row:
|
|||
inc esi
|
||||
cmp esi,8
|
||||
jb slot_render_pay_row
|
||||
invoke DrawString8x8,62,181,OFFSET slotPairText3D,00A8DDB9h
|
||||
invoke DrawString8x8,62,192,OFFSET slotCherryPair3D,00A8DDB9h
|
||||
invoke DrawString8x8,62,160,OFFSET slotPairText3D,00A8DDB9h
|
||||
invoke DrawString8x8,62,173,OFFSET slotCherryPair3D,00A8DDB9h
|
||||
invoke DrawString8x8,42,188,OFFSET slotPayNote3D,00A8DDB9h
|
||||
invoke DrawBoxBorder,112,204,96,15,003B6C59h,00E9D8B0h,1
|
||||
invoke DrawString8x8,128,207,OFFSET slotCloseText3D,00E9D8B0h
|
||||
slot_render_done:
|
||||
ret
|
||||
RenderNativeSlots3D ENDP
|
||||
|
||||
; Gross is the actual credited sum, including any returned stake.
|
||||
DrawSlotTotals3D PROC uses ebx esi edi gross:DWORD,stake:DWORD,x:DWORD
|
||||
mov ebx,x
|
||||
lea edi,[ebx+72]
|
||||
invoke DrawString8x8,ebx,201,OFFSET slotWinText3D,00E8D7ADh
|
||||
invoke FormatNumber,gross,OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,edi,201,OFFSET hudNumBuffer,00F4F3E8h
|
||||
invoke DrawString8x8,ebx,211,OFFSET slotNetText3D,00E8D7ADh
|
||||
mov eax,gross
|
||||
sub eax,stake
|
||||
mov esi,00D0D4D0h
|
||||
lea ebx,slotNetBuffer3D
|
||||
test eax,eax
|
||||
jz totals_format
|
||||
mov BYTE PTR [ebx],'+'
|
||||
mov esi,00A8DDB9h
|
||||
jns @F
|
||||
mov BYTE PTR [ebx],'-'
|
||||
mov esi,00EE9988h
|
||||
neg eax
|
||||
@@:
|
||||
inc ebx
|
||||
totals_format:
|
||||
invoke FormatNumber,eax,ebx
|
||||
invoke DrawString8x8,edi,211,OFFSET slotNetBuffer3D,esi
|
||||
ret
|
||||
DrawSlotTotals3D ENDP
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ SlotExitMouse3D PROTO
|
|||
SlotReelPosition3D PROTO :DWORD
|
||||
DrawSlotReel3D PROTO :DWORD
|
||||
DrawSlotSymbol3D PROTO :DWORD,:DWORD,:DWORD
|
||||
DrawSlotTotals3D PROTO :DWORD,:DWORD,:DWORD
|
||||
.data
|
||||
slotCabinetPack3D AnimPack3D <>
|
||||
slotSymbolsPack3D AnimPack3D <>
|
||||
|
|
@ -38,6 +39,9 @@ slotLeaveAfter3D dd 0
|
|||
slotPaytable3D dd 0
|
||||
slotError3D dd 0
|
||||
slotEffects3D dd 0
|
||||
slotNetBuffer3D db 16 dup(0)
|
||||
slotRefundText3D db 194,206,199,194,208,192,210,0
|
||||
slotNetText3D db 200,210,206,195,0
|
||||
slotTitle3D db "777",0
|
||||
slotSpinText3D db 194,208,192,217,192,210,220,0
|
||||
slotPayText3D db 194,219,207,203,192,210,219,0
|
||||
|
|
@ -50,7 +54,7 @@ slotRollingText3D db 194,208,192,217,197,205,200,197,0
|
|||
slotExitText3D db 199,192,194,197,208,216,197,205,200,197,0
|
||||
slotLoseText3D db 207,208,206,200,195,208,219,216,0
|
||||
slotNoMoney3D db 205,197,210,32,196,197,205,197,195,0
|
||||
slotTripleText3D db 210,208,200,32,209,200,204,194,206,203,192,32,40,209,206,32,209,210,192,194,202,206,201,41,0
|
||||
slotTripleText3D db 214,197,205,210,208,58,32,210,208,200,32,206,196,200,205,192,202,206,194,219,213,0
|
||||
strMultiplier3D db "x",0
|
||||
slotPairText3D db 203,222,193,192,223,32,207,192,208,192,32,32,32,32,"x1",0
|
||||
slotCherryPair3D db 207,192,208,192,32,194,200,216,197,205,32,32,32,32,"x2",0
|
||||
|
|
|
|||
|
|
@ -132,6 +132,11 @@ wheel_bank_cap:
|
|||
mov bankroll, 1000000000
|
||||
@@:
|
||||
mov roulState, 2
|
||||
xor eax,eax
|
||||
mov ecx,wheelReturn3D
|
||||
cmp ecx,wheelStake3D
|
||||
seta al
|
||||
invoke NpcRecordRound3D,3,eax
|
||||
call SaveProgress3D
|
||||
wheel_settle_done:
|
||||
ret
|
||||
|
|
@ -740,7 +745,7 @@ wheel_ball_place:
|
|||
cmp roulState,2
|
||||
jne wheel_scene_done
|
||||
invoke DrawWheelLabels3D,centerX,centerY,radiusX,radiusY,wheelRotorAngle3D
|
||||
invoke DrawBuckshotPanel3D,278,245,84,61,002D211Bh
|
||||
invoke DrawWheelBox3D,278,245,84,61,002D211Bh
|
||||
invoke DrawBuckshotText3D,296,253,OFFSET wheelLandedText3D,00E5D29Eh
|
||||
mov ecx,00F4E7C8h
|
||||
cmp wheelResult3D,0
|
||||
|
|
@ -755,9 +760,56 @@ wheel_scene_done:
|
|||
ret
|
||||
RenderWheelScene3D ENDP
|
||||
|
||||
; Exact framebuffer rectangles avoid the two-pixel rounding of the logical UI grid.
|
||||
DrawWheelBox3D PROC uses ebx esi edi x:DWORD,y:DWORD,w:DWORD,h:DWORD,ink:DWORD
|
||||
local bottom:DWORD
|
||||
mov esi,x
|
||||
test esi,esi
|
||||
jns @F
|
||||
xor esi,esi
|
||||
@@:
|
||||
mov eax,x
|
||||
add eax,w
|
||||
cmp eax,SCREEN_W
|
||||
jle @F
|
||||
mov eax,SCREEN_W
|
||||
@@:
|
||||
sub eax,esi
|
||||
jle wheel_box_done
|
||||
mov ebx,eax
|
||||
mov edx,y
|
||||
test edx,edx
|
||||
jns @F
|
||||
xor edx,edx
|
||||
@@:
|
||||
mov eax,y
|
||||
add eax,h
|
||||
cmp eax,SCREEN_H
|
||||
jle @F
|
||||
mov eax,SCREEN_H
|
||||
@@:
|
||||
cmp eax,edx
|
||||
jle wheel_box_done
|
||||
mov bottom,eax
|
||||
wheel_box_row:
|
||||
imul edi,edx,SCREEN_W
|
||||
add edi,esi
|
||||
lea edi,screenBuffer[edi*4]
|
||||
mov eax,ink
|
||||
mov ecx,ebx
|
||||
rep stosd
|
||||
inc edx
|
||||
cmp edx,bottom
|
||||
jl wheel_box_row
|
||||
wheel_box_done:
|
||||
ret
|
||||
DrawWheelBox3D ENDP
|
||||
|
||||
; Upright screen-space digits retain their shape when the wheel is projected.
|
||||
DrawWheelDigit3D PROC uses ebx esi edi x:DWORD,y:DWORD,digit:DWORD,scale:DWORD,ink:DWORD
|
||||
local row:DWORD,column:DWORD,bits:DWORD,px:DWORD,py:DWORD
|
||||
cmp scale,0
|
||||
je wheel_digit_done
|
||||
cmp digit,9
|
||||
ja wheel_digit_done
|
||||
mov eax,digit
|
||||
|
|
@ -780,7 +832,7 @@ wheel_digit_column:
|
|||
imul eax,scale
|
||||
add eax,y
|
||||
mov py,eax
|
||||
invoke DrawBuckshotPanel3D,px,py,scale,scale,ink
|
||||
invoke DrawWheelBox3D,px,py,scale,scale,ink
|
||||
wheel_digit_next:
|
||||
shl bits,1
|
||||
inc column
|
||||
|
|
@ -885,10 +937,10 @@ wheel_label_highlight:
|
|||
mov edi,wheelNumberY3D[esi*4]
|
||||
sub ebx,9
|
||||
sub edi,6
|
||||
invoke DrawBuckshotPanel3D,ebx,edi,18,12,00E5C978h
|
||||
invoke DrawWheelBox3D,ebx,edi,18,12,00E5C978h
|
||||
inc ebx
|
||||
inc edi
|
||||
invoke DrawBuckshotPanel3D,ebx,edi,16,10,00121916h
|
||||
invoke DrawWheelBox3D,ebx,edi,16,10,00121916h
|
||||
mov eax,wheelNumberY3D[esi*4]
|
||||
sub eax,5
|
||||
invoke DrawWheelValue3D,wheelNumberX3D[esi*4],eax,wheelResult3D,2,00FFF8DEh
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ WheelTravel3D PROTO :DWORD,:DWORD,:DWORD
|
|||
DrawNativeWheelDisc3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
RenderWheelScene3D PROTO
|
||||
DrawWheelDigit3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
DrawWheelBox3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
DrawWheelValue3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
DrawWheelLabels3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
.data
|
||||
|
|
|
|||
437
src_graphics/npc_contracts.inc
Normal file
|
|
@ -0,0 +1,437 @@
|
|||
NpcDate3D PROC
|
||||
IFDEF CASINO_ACTION_TEST
|
||||
mov eax,npcDateOverride3D
|
||||
test eax,eax
|
||||
jnz npc_date_done
|
||||
ENDIF
|
||||
invoke GetLocalTime,OFFSET npcSystemTime3D
|
||||
movzx eax,npcSystemTime3D
|
||||
imul eax,10000
|
||||
movzx ecx,npcSystemTime3D[2]
|
||||
imul ecx,100
|
||||
add eax,ecx
|
||||
movzx ecx,npcSystemTime3D[6]
|
||||
add eax,ecx
|
||||
npc_date_done:
|
||||
ret
|
||||
NpcDate3D ENDP
|
||||
|
||||
NpcJournalSignature3D PROC uses esi source:DWORD
|
||||
mov esi,source
|
||||
mov ecx,(NPC_JOURNAL_SIZE-4)/4
|
||||
mov eax,4E504351h
|
||||
npc_signature_word:
|
||||
rol eax,5
|
||||
xor eax,[esi]
|
||||
add eax,9E3779B9h
|
||||
add esi,4
|
||||
loop npc_signature_word
|
||||
ret
|
||||
NpcJournalSignature3D ENDP
|
||||
|
||||
; Failed, truncated or mismatched journals cannot change the player's balance.
|
||||
NpcEnsureJournal3D PROC uses ebx esi edi
|
||||
local date:DWORD,io:DWORD
|
||||
call NpcDate3D
|
||||
mov date,eax
|
||||
mov esi,OFFSET savePath3D
|
||||
cmp nativeProfileActive3D,0
|
||||
je @F
|
||||
mov esi,OFFSET saveFullPath
|
||||
@@:
|
||||
IFDEF CASINO_ACTION_TEST
|
||||
cmp npcJournalBasePtr3D,0
|
||||
je @F
|
||||
mov esi,npcJournalBasePtr3D
|
||||
@@:
|
||||
ENDIF
|
||||
xor ecx,ecx
|
||||
npc_journal_path_length:
|
||||
cmp ecx,250
|
||||
jae npc_journal_invalid_path
|
||||
cmp BYTE PTR [esi+ecx],0
|
||||
je npc_journal_build_path
|
||||
inc ecx
|
||||
jmp npc_journal_path_length
|
||||
npc_journal_build_path:
|
||||
invoke CopyCString,OFFSET npcJournalNextPath3D,esi
|
||||
invoke AppendCString,OFFSET npcJournalNextPath3D,OFFSET npcJournalSuffix3D
|
||||
invoke lstrcmpiA,OFFSET npcJournalPath3D,OFFSET npcJournalNextPath3D
|
||||
test eax,eax
|
||||
jnz npc_journal_reset
|
||||
cmp npcJournalLoaded3D,1
|
||||
jne npc_journal_reset
|
||||
mov eax,date
|
||||
cmp eax,npcJournalDay3D
|
||||
je npc_journal_ready
|
||||
npc_journal_reset:
|
||||
mov npcAccepted3D,0
|
||||
mov npcClaimed3D,0
|
||||
lea edi,npcProgress3D
|
||||
mov ecx,NPC_IDENTITY_COUNT
|
||||
xor eax,eax
|
||||
rep stosd
|
||||
mov eax,date
|
||||
mov npcJournalDay3D,eax
|
||||
invoke CopyCString,OFFSET npcJournalPath3D,OFFSET npcJournalNextPath3D
|
||||
mov npcJournalLoaded3D,1
|
||||
invoke CreateFileA,OFFSET npcJournalPath3D,80000000h,1,0,3,80h,0
|
||||
cmp eax,-1
|
||||
je npc_journal_ready
|
||||
mov ebx,eax
|
||||
invoke GetFileSize,ebx,0
|
||||
cmp eax,NPC_JOURNAL_SIZE
|
||||
jne npc_journal_close
|
||||
invoke ReadFile,ebx,OFFSET npcJournalRead3D,NPC_JOURNAL_SIZE,ADDR io,0
|
||||
test eax,eax
|
||||
jz npc_journal_close
|
||||
cmp io,NPC_JOURNAL_SIZE
|
||||
jne npc_journal_close
|
||||
cmp DWORD PTR npcJournalRead3D,3151504Eh
|
||||
jne npc_journal_close
|
||||
mov eax,date
|
||||
cmp DWORD PTR npcJournalRead3D[4],eax
|
||||
jne npc_journal_close
|
||||
mov eax,DWORD PTR npcJournalRead3D[8]
|
||||
or eax,DWORD PTR npcJournalRead3D[12]
|
||||
test eax,0FFFFF000h
|
||||
jnz npc_journal_close
|
||||
mov eax,DWORD PTR npcJournalRead3D[12]
|
||||
not eax
|
||||
or eax,DWORD PTR npcJournalRead3D[8]
|
||||
cmp eax,-1
|
||||
jne npc_journal_close
|
||||
invoke NpcJournalSignature3D,OFFSET npcJournalRead3D
|
||||
cmp eax,DWORD PTR npcJournalRead3D[NPC_JOURNAL_SIZE-4]
|
||||
jne npc_journal_close
|
||||
xor esi,esi
|
||||
npc_journal_validate_progress:
|
||||
invoke NpcContractType3D,esi
|
||||
mov eax,npcQuestGoals3D[eax*4]
|
||||
cmp DWORD PTR npcJournalRead3D[16+esi*4],eax
|
||||
ja npc_journal_close
|
||||
inc esi
|
||||
cmp esi,NPC_IDENTITY_COUNT
|
||||
jb npc_journal_validate_progress
|
||||
lea esi,npcJournalRead3D
|
||||
lea edi,npcJournal3D
|
||||
mov ecx,NPC_JOURNAL_SIZE/4
|
||||
rep movsd
|
||||
npc_journal_close:
|
||||
invoke CloseHandle,ebx
|
||||
npc_journal_ready:
|
||||
mov eax,1
|
||||
ret
|
||||
npc_journal_invalid_path:
|
||||
mov npcJournalLoaded3D,0
|
||||
mov npcJournalIoError3D,1
|
||||
xor eax,eax
|
||||
ret
|
||||
NpcEnsureJournal3D ENDP
|
||||
|
||||
NpcSaveJournal3D PROC uses ebx
|
||||
local io:DWORD,ok:DWORD
|
||||
mov npcJournalIoError3D,0
|
||||
cmp npcJournalLoaded3D,1
|
||||
jne npc_journal_write_fail
|
||||
invoke NpcJournalSignature3D,OFFSET npcJournal3D
|
||||
mov npcJournalChecksum3D,eax
|
||||
invoke CreateDirectoryA,OFFSET runtime3D,0
|
||||
invoke CreateFileA,OFFSET npcJournalPath3D,40000000h,0,0,2,80h,0
|
||||
cmp eax,-1
|
||||
je npc_journal_write_fail
|
||||
mov ebx,eax
|
||||
invoke WriteFile,ebx,OFFSET npcJournal3D,NPC_JOURNAL_SIZE,ADDR io,0
|
||||
mov ok,eax
|
||||
invoke CloseHandle,ebx
|
||||
cmp ok,0
|
||||
je npc_journal_write_fail
|
||||
cmp io,NPC_JOURNAL_SIZE
|
||||
jne npc_journal_write_fail
|
||||
mov eax,1
|
||||
ret
|
||||
npc_journal_write_fail:
|
||||
mov npcJournalIoError3D,1
|
||||
xor eax,eax
|
||||
ret
|
||||
NpcSaveJournal3D ENDP
|
||||
|
||||
NpcContractType3D PROC identity:DWORD
|
||||
mov eax,npcJournalDay3D
|
||||
mov ecx,identity
|
||||
imul ecx,7
|
||||
add eax,ecx
|
||||
xor edx,edx
|
||||
mov ecx,NPC_IDENTITY_COUNT
|
||||
div ecx
|
||||
mov eax,edx
|
||||
ret
|
||||
NpcContractType3D ENDP
|
||||
|
||||
NpcAcceptContract3D PROC uses ebx identity:DWORD
|
||||
mov npcJournalIoError3D,0
|
||||
cmp identity,NPC_IDENTITY_COUNT
|
||||
jae npc_accept_fail
|
||||
call NpcEnsureJournal3D
|
||||
test eax,eax
|
||||
jz npc_accept_fail
|
||||
mov ebx,identity
|
||||
bt npcAccepted3D,ebx
|
||||
jc npc_accept_fail
|
||||
bts npcAccepted3D,ebx
|
||||
call NpcSaveJournal3D
|
||||
test eax,eax
|
||||
jnz npc_accept_done
|
||||
btr npcAccepted3D,ebx
|
||||
npc_accept_fail:
|
||||
xor eax,eax
|
||||
npc_accept_done:
|
||||
ret
|
||||
NpcAcceptContract3D ENDP
|
||||
|
||||
NpcRecordRound3D PROC uses ebx esi edi game:DWORD,won:DWORD
|
||||
call NpcEnsureJournal3D
|
||||
test eax,eax
|
||||
jz npc_event_done
|
||||
cmp npcAccepted3D,0
|
||||
je npc_event_done
|
||||
xor esi,esi
|
||||
xor edi,edi
|
||||
npc_event_contract:
|
||||
bt npcAccepted3D,esi
|
||||
jnc npc_event_next
|
||||
bt npcClaimed3D,esi
|
||||
jc npc_event_next
|
||||
invoke NpcContractType3D,esi
|
||||
mov ebx,eax
|
||||
mov eax,npcQuestGames3D[ebx*4]
|
||||
cmp eax,-1
|
||||
je @F
|
||||
cmp eax,game
|
||||
jne npc_event_next
|
||||
@@:
|
||||
cmp npcQuestWins3D[ebx*4],0
|
||||
je @F
|
||||
cmp won,0
|
||||
je npc_event_next
|
||||
@@:
|
||||
mov eax,npcQuestGoals3D[ebx*4]
|
||||
cmp npcProgress3D[esi*4],eax
|
||||
jae npc_event_next
|
||||
inc npcProgress3D[esi*4]
|
||||
mov edi,1
|
||||
npc_event_next:
|
||||
inc esi
|
||||
cmp esi,NPC_IDENTITY_COUNT
|
||||
jb npc_event_contract
|
||||
test edi,edi
|
||||
jz npc_event_done
|
||||
call NpcSaveJournal3D
|
||||
npc_event_done:
|
||||
ret
|
||||
NpcRecordRound3D ENDP
|
||||
|
||||
NpcClaimContract3D PROC uses ebx esi identity:DWORD
|
||||
mov npcJournalIoError3D,0
|
||||
cmp identity,NPC_IDENTITY_COUNT
|
||||
jae npc_claim_fail
|
||||
call NpcEnsureJournal3D
|
||||
test eax,eax
|
||||
jz npc_claim_fail
|
||||
mov ebx,identity
|
||||
bt npcAccepted3D,ebx
|
||||
jnc npc_claim_fail
|
||||
bt npcClaimed3D,ebx
|
||||
jc npc_claim_fail
|
||||
invoke NpcContractType3D,ebx
|
||||
mov ecx,npcQuestGoals3D[eax*4]
|
||||
cmp npcProgress3D[ebx*4],ecx
|
||||
jb npc_claim_fail
|
||||
mov esi,npcQuestRewards3D[eax*4]
|
||||
bts npcClaimed3D,ebx
|
||||
call NpcSaveJournal3D
|
||||
test eax,eax
|
||||
jnz npc_claim_credit
|
||||
btr npcClaimed3D,ebx
|
||||
jmp npc_claim_fail
|
||||
npc_claim_credit:
|
||||
add bankroll,esi
|
||||
jc @F
|
||||
cmp bankroll,1000000000
|
||||
jbe npc_claim_save
|
||||
@@:
|
||||
mov bankroll,1000000000
|
||||
npc_claim_save:
|
||||
call SaveProgress3D
|
||||
mov eax,1
|
||||
ret
|
||||
npc_claim_fail:
|
||||
xor eax,eax
|
||||
ret
|
||||
NpcClaimContract3D ENDP
|
||||
|
||||
OpenNpcDialog3D PROC uses ebx
|
||||
cmp npcSelected3D,NPC_LIFE_COUNT
|
||||
jae npc_dialog_open_fail
|
||||
imul ebx,npcSelected3D,SIZEOF NpcLife3D
|
||||
cmp npcLife3D[ebx].state,NPC_AWAY
|
||||
je npc_dialog_open_fail
|
||||
mov eax,npcLife3D[ebx].identity
|
||||
mov npcDialogIdentity3D,eax
|
||||
mov npcDialogError3D,0
|
||||
call NpcEnsureJournal3D
|
||||
test eax,eax
|
||||
jnz @F
|
||||
mov npcDialogError3D,1
|
||||
@@:
|
||||
mov engineMode,MODE_NPC_DIALOG
|
||||
call ClearKeys3D
|
||||
mov eax,1
|
||||
ret
|
||||
npc_dialog_open_fail:
|
||||
xor eax,eax
|
||||
ret
|
||||
OpenNpcDialog3D ENDP
|
||||
|
||||
CloseNpcDialog3D PROC
|
||||
mov engineMode,MODE_WALK
|
||||
mov paused3D,0
|
||||
call ClearKeys3D
|
||||
ret
|
||||
CloseNpcDialog3D ENDP
|
||||
|
||||
HandleNpcDialog3D PROC
|
||||
cmp engineMode,MODE_NPC_DIALOG
|
||||
jne npc_dialog_handle_done
|
||||
call NpcEnsureJournal3D
|
||||
cmp mouseClick3D,0
|
||||
je npc_dialog_keys
|
||||
mov mouseClick3D,0
|
||||
cmp mouseY3D,169
|
||||
jb npc_dialog_keys
|
||||
cmp mouseY3D,190
|
||||
jae npc_dialog_keys
|
||||
cmp mouseX3D,40
|
||||
jb npc_dialog_keys
|
||||
cmp mouseX3D,112
|
||||
jb npc_dialog_accept
|
||||
cmp mouseX3D,120
|
||||
jb npc_dialog_keys
|
||||
cmp mouseX3D,198
|
||||
jb npc_dialog_claim
|
||||
cmp mouseX3D,208
|
||||
jb npc_dialog_keys
|
||||
cmp mouseX3D,280
|
||||
jb npc_dialog_close
|
||||
npc_dialog_keys:
|
||||
invoke Pressed3D,30h
|
||||
test eax,eax
|
||||
jnz npc_dialog_close
|
||||
invoke Pressed3D,31h
|
||||
test eax,eax
|
||||
jnz npc_dialog_accept
|
||||
invoke Pressed3D,32h
|
||||
test eax,eax
|
||||
jnz npc_dialog_claim
|
||||
invoke Pressed3D,0Dh
|
||||
test eax,eax
|
||||
jz npc_dialog_handle_done
|
||||
mov ecx,npcDialogIdentity3D
|
||||
bt npcAccepted3D,ecx
|
||||
jnc npc_dialog_accept
|
||||
jmp npc_dialog_claim
|
||||
npc_dialog_accept:
|
||||
invoke NpcAcceptContract3D,npcDialogIdentity3D
|
||||
jmp npc_dialog_result
|
||||
npc_dialog_claim:
|
||||
invoke NpcClaimContract3D,npcDialogIdentity3D
|
||||
npc_dialog_result:
|
||||
mov eax,npcJournalIoError3D
|
||||
mov npcDialogError3D,eax
|
||||
ret
|
||||
npc_dialog_close:
|
||||
call CloseNpcDialog3D
|
||||
npc_dialog_handle_done:
|
||||
ret
|
||||
HandleNpcDialog3D ENDP
|
||||
|
||||
; Preserve original personality names, removing unsupported quote glyphs for the HUD.
|
||||
NpcNameText3D PROC uses esi edi identity:DWORD
|
||||
mov eax,identity
|
||||
cmp eax,NPC_IDENTITY_COUNT
|
||||
jae npc_name_empty
|
||||
mov esi,npcNames3D[eax*4]
|
||||
lea edi,npcNameBuffer3D
|
||||
mov ecx,60
|
||||
npc_name_copy:
|
||||
lodsb
|
||||
test al,al
|
||||
jz npc_name_finish
|
||||
cmp al,0ABh
|
||||
je npc_name_copy
|
||||
cmp al,0BBh
|
||||
je npc_name_copy
|
||||
stosb
|
||||
loop npc_name_copy
|
||||
npc_name_finish:
|
||||
mov BYTE PTR [edi],0
|
||||
mov eax,OFFSET npcNameBuffer3D
|
||||
ret
|
||||
npc_name_empty:
|
||||
mov npcNameBuffer3D,0
|
||||
mov eax,OFFSET npcNameBuffer3D
|
||||
ret
|
||||
NpcNameText3D ENDP
|
||||
|
||||
RenderNpcDialog3D PROC uses ebx esi
|
||||
cmp engineMode,MODE_NPC_DIALOG
|
||||
jne npc_dialog_render_done
|
||||
call RenderCeilingAndFloor
|
||||
call RenderWalls
|
||||
call PrepareCityDepth3D
|
||||
call RenderSprites
|
||||
call RenderHall3D
|
||||
invoke DrawBoxBorder,30,48,260,151,00141B1Dh,00BA9955h,1
|
||||
mov ebx,npcDialogIdentity3D
|
||||
invoke NpcNameText3D,ebx
|
||||
invoke DrawString8x8,42,59,eax,00F4DF9Eh
|
||||
mov eax,ebx
|
||||
xor edx,edx
|
||||
mov ecx,6
|
||||
div ecx
|
||||
invoke DrawString8x8,42,76,npcGreetings3D[edx*4],00CED8D5h
|
||||
invoke DrawString8x8,42,97,OFFSET npcContractTitle3D,00D3C08Fh
|
||||
invoke NpcContractType3D,ebx
|
||||
mov esi,eax
|
||||
invoke DrawString8x8,42,112,npcQuestTexts3D[esi*4],00FFFFFFh
|
||||
invoke DrawString8x8,42,130,OFFSET npcProgressText3D,00CED8D5h
|
||||
invoke DrawNumber,112,130,npcProgress3D[ebx*4],00FFFFFFh
|
||||
invoke DrawString8x8,123,130,OFFSET npcSlashText3D,00CED8D5h
|
||||
invoke DrawNumber,149,130,npcQuestGoals3D[esi*4],00FFFFFFh
|
||||
invoke DrawString8x8,178,130,OFFSET npcRewardText3D,00D3C08Fh
|
||||
invoke DrawNumber,244,130,npcQuestRewards3D[esi*4],00FFFFFFh
|
||||
mov eax,OFFSET npcAvailableText3D
|
||||
bt npcAccepted3D,ebx
|
||||
jnc npc_dialog_status
|
||||
mov eax,OFFSET npcActiveText3D
|
||||
mov ecx,npcQuestGoals3D[esi*4]
|
||||
cmp npcProgress3D[ebx*4],ecx
|
||||
jb npc_dialog_status
|
||||
mov eax,OFFSET npcReadyText3D
|
||||
bt npcClaimed3D,ebx
|
||||
jnc npc_dialog_status
|
||||
mov eax,OFFSET npcDoneText3D
|
||||
npc_dialog_status:
|
||||
invoke DrawString8x8,42,150,eax,0087D4A5h
|
||||
invoke DrawBoxBorder,40,170,72,18,002D3A32h,0087AA8Eh,1
|
||||
invoke DrawString8x8,51,175,OFFSET npcAcceptText3D,00FFFFFFh
|
||||
invoke DrawBoxBorder,120,170,78,18,003B3024h,00BA9955h,1
|
||||
invoke DrawString8x8,131,175,OFFSET npcClaimText3D,00FFFFFFh
|
||||
invoke DrawBoxBorder,208,170,72,18,00212A2Dh,008B999Ah,1
|
||||
invoke DrawString8x8,216,175,OFFSET npcCloseText3D,00FFFFFFh
|
||||
cmp npcDialogError3D,0
|
||||
je npc_dialog_render_done
|
||||
invoke DrawString8x8,42,150,OFFSET npcIoErrorText3D,00F89880h
|
||||
npc_dialog_render_done:
|
||||
ret
|
||||
RenderNpcDialog3D ENDP
|
||||
581
src_graphics/npc_life.inc
Normal file
|
|
@ -0,0 +1,581 @@
|
|||
; The visible people and the user's personality records share the same positions.
|
||||
InitNpcLife3D PROC uses ebx esi edi
|
||||
xor esi,esi
|
||||
mov npcLifeClock3D,0
|
||||
mov npcSelected3D,-1
|
||||
npc_life_init:
|
||||
imul ebx,esi,SIZEOF NpcLife3D
|
||||
mov npcLife3D[ebx].identity,esi
|
||||
mov npcLife3D[ebx].state,NPC_STAND
|
||||
mov eax,esi
|
||||
imul eax,900
|
||||
add eax,1800
|
||||
mov npcLife3D[ebx].remaining,eax
|
||||
mov npcLife3D[ebx].routeStep,esi
|
||||
mov npcLife3D[ebx].pathCount,0
|
||||
mov npcLife3D[ebx].remainder,0
|
||||
mov npcLife3D[ebx].poseClock,0
|
||||
mov eax,npcStartDest3D[esi*4]
|
||||
mov npcLife3D[ebx].destination,eax
|
||||
imul edi,esi,SIZEOF NpcMindEntity
|
||||
mov ecx,npcDestX3D[eax*4]
|
||||
mov casinoNpcs3D[edi].posX,ecx
|
||||
mov ecx,npcDestY3D[eax*4]
|
||||
mov casinoNpcs3D[edi].posY,ecx
|
||||
cmp eax,7
|
||||
je @F
|
||||
cmp eax,8
|
||||
jne npc_life_init_next
|
||||
@@:
|
||||
mov npcLife3D[ebx].state,NPC_SIT
|
||||
npc_life_init_next:
|
||||
inc esi
|
||||
cmp esi,NPC_LIFE_COUNT
|
||||
jb npc_life_init
|
||||
mov npcLifeReady3D,1
|
||||
ret
|
||||
InitNpcLife3D ENDP
|
||||
|
||||
; BFS visits each tile at most once. Body clearance includes furniture and the stage.
|
||||
NpcTryCell3D PROC uses ebx esi cell:DWORD,parent:DWORD
|
||||
mov esi,cell
|
||||
cmp esi,NPC_PATH_CAP
|
||||
jae npc_cell_done
|
||||
cmp npcParents3D[esi*4],-1
|
||||
jne npc_cell_done
|
||||
mov eax,esi
|
||||
and eax,31
|
||||
shl eax,16
|
||||
add eax,FP_HALF
|
||||
mov edx,esi
|
||||
shr edx,5
|
||||
shl edx,16
|
||||
add edx,FP_HALF
|
||||
invoke CanWalk3D,eax,edx
|
||||
test eax,eax
|
||||
jz npc_cell_done
|
||||
mov eax,parent
|
||||
mov npcParents3D[esi*4],eax
|
||||
mov ebx,npcSearchTail3D
|
||||
cmp ebx,NPC_PATH_CAP
|
||||
jae npc_cell_done
|
||||
mov npcQueue3D[ebx*4],esi
|
||||
inc npcSearchTail3D
|
||||
npc_cell_done:
|
||||
ret
|
||||
NpcTryCell3D ENDP
|
||||
|
||||
NpcPlanPath3D PROC uses ebx esi edi slot:DWORD,destination:DWORD
|
||||
local firstCell:DWORD,currentCell:DWORD,pathBase:DWORD
|
||||
cmp slot,NPC_LIFE_COUNT
|
||||
jae npc_plan_fail
|
||||
cmp destination,NPC_DEST_COUNT
|
||||
jae npc_plan_fail
|
||||
imul ebx,slot,SIZEOF NpcLife3D
|
||||
mov npcLife3D[ebx].pathCount,0
|
||||
imul esi,slot,SIZEOF NpcMindEntity
|
||||
mov eax,casinoNpcs3D[esi].posY
|
||||
sar eax,16
|
||||
shl eax,5
|
||||
mov ecx,casinoNpcs3D[esi].posX
|
||||
sar ecx,16
|
||||
add eax,ecx
|
||||
cmp eax,NPC_PATH_CAP
|
||||
jae npc_plan_fail
|
||||
mov firstCell,eax
|
||||
mov ecx,destination
|
||||
mov eax,npcDestY3D[ecx*4]
|
||||
sar eax,16
|
||||
shl eax,5
|
||||
mov edx,npcDestX3D[ecx*4]
|
||||
sar edx,16
|
||||
add eax,edx
|
||||
mov npcSearchGoal3D,eax
|
||||
lea edi,npcParents3D
|
||||
mov ecx,NPC_PATH_CAP
|
||||
mov eax,-1
|
||||
rep stosd
|
||||
mov eax,firstCell
|
||||
mov npcParents3D[eax*4],eax
|
||||
mov npcQueue3D,eax
|
||||
mov npcSearchHead3D,0
|
||||
mov npcSearchTail3D,1
|
||||
npc_plan_search:
|
||||
mov eax,npcSearchHead3D
|
||||
cmp eax,npcSearchTail3D
|
||||
jae npc_plan_fail
|
||||
mov esi,npcQueue3D[eax*4]
|
||||
inc npcSearchHead3D
|
||||
cmp esi,npcSearchGoal3D
|
||||
je npc_plan_found
|
||||
mov eax,esi
|
||||
and eax,31
|
||||
test eax,eax
|
||||
jz @F
|
||||
lea eax,[esi-1]
|
||||
invoke NpcTryCell3D,eax,esi
|
||||
@@:
|
||||
mov eax,esi
|
||||
and eax,31
|
||||
cmp eax,31
|
||||
je @F
|
||||
lea eax,[esi+1]
|
||||
invoke NpcTryCell3D,eax,esi
|
||||
@@:
|
||||
cmp esi,32
|
||||
jb @F
|
||||
lea eax,[esi-32]
|
||||
invoke NpcTryCell3D,eax,esi
|
||||
@@:
|
||||
cmp esi,NPC_PATH_CAP-32
|
||||
jae npc_plan_search
|
||||
lea eax,[esi+32]
|
||||
invoke NpcTryCell3D,eax,esi
|
||||
jmp npc_plan_search
|
||||
npc_plan_found:
|
||||
mov eax,slot
|
||||
imul eax,NPC_PATH_CAP*4
|
||||
add eax,OFFSET npcPaths3D
|
||||
mov pathBase,eax
|
||||
xor edi,edi
|
||||
npc_plan_reverse:
|
||||
cmp esi,firstCell
|
||||
je npc_plan_success
|
||||
cmp edi,NPC_PATH_CAP
|
||||
jae npc_plan_fail
|
||||
mov edx,pathBase
|
||||
mov [edx+edi*4],esi
|
||||
inc edi
|
||||
mov esi,npcParents3D[esi*4]
|
||||
jmp npc_plan_reverse
|
||||
npc_plan_success:
|
||||
mov npcLife3D[ebx].pathCount,edi
|
||||
mov eax,destination
|
||||
mov npcLife3D[ebx].destination,eax
|
||||
mov eax,1
|
||||
ret
|
||||
npc_plan_fail:
|
||||
xor eax,eax
|
||||
ret
|
||||
NpcPlanPath3D ENDP
|
||||
|
||||
NpcCanStep3D PROC uses ebx esi slot:DWORD,px:DWORD,py:DWORD
|
||||
invoke CanWalk3D,px,py
|
||||
test eax,eax
|
||||
jz npc_space_done
|
||||
mov eax,px
|
||||
sub eax,playerX
|
||||
jns @F
|
||||
neg eax
|
||||
@@:
|
||||
cmp eax,FP_1*3/10
|
||||
jae npc_space_people
|
||||
mov eax,py
|
||||
sub eax,playerY
|
||||
jns @F
|
||||
neg eax
|
||||
@@:
|
||||
cmp eax,FP_1*3/10
|
||||
jb npc_space_blocked
|
||||
npc_space_people:
|
||||
xor esi,esi
|
||||
npc_space_person:
|
||||
cmp esi,slot
|
||||
je npc_space_next
|
||||
imul ebx,esi,SIZEOF NpcLife3D
|
||||
cmp npcLife3D[ebx].state,NPC_AWAY
|
||||
je npc_space_next
|
||||
imul ebx,esi,SIZEOF NpcMindEntity
|
||||
mov eax,px
|
||||
sub eax,casinoNpcs3D[ebx].posX
|
||||
jns @F
|
||||
neg eax
|
||||
@@:
|
||||
cmp eax,FP_1*2/5
|
||||
jae npc_space_next
|
||||
mov eax,py
|
||||
sub eax,casinoNpcs3D[ebx].posY
|
||||
jns @F
|
||||
neg eax
|
||||
@@:
|
||||
cmp eax,FP_1*2/5
|
||||
jb npc_space_blocked
|
||||
npc_space_next:
|
||||
inc esi
|
||||
cmp esi,NPC_LIFE_COUNT
|
||||
jb npc_space_person
|
||||
mov eax,1
|
||||
ret
|
||||
npc_space_blocked:
|
||||
xor eax,eax
|
||||
npc_space_done:
|
||||
ret
|
||||
NpcCanStep3D ENDP
|
||||
|
||||
; Millisecond movement, carrying the remainder and consuming whole route cells.
|
||||
NpcMove3D PROC uses ebx esi edi slot:DWORD,milliseconds:DWORD
|
||||
local budget:DWORD,wx:DWORD,wy:DWORD,mind:DWORD,pathBase:DWORD
|
||||
imul ebx,slot,SIZEOF NpcLife3D
|
||||
imul eax,slot,SIZEOF NpcMindEntity
|
||||
lea esi,casinoNpcs3D[eax]
|
||||
mov mind,esi
|
||||
mov eax,slot
|
||||
imul eax,NPC_PATH_CAP*4
|
||||
add eax,OFFSET npcPaths3D
|
||||
mov pathBase,eax
|
||||
mov eax,milliseconds
|
||||
mov ecx,55000
|
||||
mul ecx
|
||||
add eax,npcLife3D[ebx].remainder
|
||||
adc edx,0
|
||||
mov ecx,1000
|
||||
div ecx
|
||||
mov npcLife3D[ebx].remainder,edx
|
||||
mov budget,eax
|
||||
npc_move_cell:
|
||||
mov eax,npcLife3D[ebx].pathCount
|
||||
test eax,eax
|
||||
jz npc_move_arrived
|
||||
dec eax
|
||||
mov edx,pathBase
|
||||
mov edi,[edx+eax*4]
|
||||
mov eax,edi
|
||||
and eax,31
|
||||
shl eax,16
|
||||
add eax,FP_HALF
|
||||
mov wx,eax
|
||||
mov eax,edi
|
||||
shr eax,5
|
||||
shl eax,16
|
||||
add eax,FP_HALF
|
||||
mov wy,eax
|
||||
mov esi,mind
|
||||
mov eax,wx
|
||||
sub eax,[esi].NpcMindEntity.posX
|
||||
mov edi,1
|
||||
test eax,eax
|
||||
jns @F
|
||||
neg eax
|
||||
mov edi,-1
|
||||
@@:
|
||||
test eax,eax
|
||||
jz npc_move_y
|
||||
cmp eax,budget
|
||||
jbe @F
|
||||
mov eax,budget
|
||||
@@:
|
||||
sub budget,eax
|
||||
imul eax,edi
|
||||
add eax,[esi].NpcMindEntity.posX
|
||||
mov wx,eax
|
||||
invoke NpcCanStep3D,slot,wx,[esi].NpcMindEntity.posY
|
||||
test eax,eax
|
||||
jz npc_move_blocked
|
||||
mov eax,wx
|
||||
mov [esi].NpcMindEntity.posX,eax
|
||||
npc_move_y:
|
||||
mov eax,wy
|
||||
sub eax,[esi].NpcMindEntity.posY
|
||||
mov edi,1
|
||||
test eax,eax
|
||||
jns @F
|
||||
neg eax
|
||||
mov edi,-1
|
||||
@@:
|
||||
cmp eax,budget
|
||||
jbe @F
|
||||
mov eax,budget
|
||||
@@:
|
||||
sub budget,eax
|
||||
imul eax,edi
|
||||
add eax,[esi].NpcMindEntity.posY
|
||||
mov wy,eax
|
||||
invoke NpcCanStep3D,slot,[esi].NpcMindEntity.posX,wy
|
||||
test eax,eax
|
||||
jz npc_move_blocked
|
||||
mov eax,wy
|
||||
mov [esi].NpcMindEntity.posY,eax
|
||||
mov edx,pathBase
|
||||
mov eax,npcLife3D[ebx].pathCount
|
||||
dec eax
|
||||
mov edi,[edx+eax*4]
|
||||
mov eax,[esi].NpcMindEntity.posX
|
||||
sub eax,FP_HALF
|
||||
sar eax,16
|
||||
mov edx,[esi].NpcMindEntity.posY
|
||||
sub edx,FP_HALF
|
||||
sar edx,16
|
||||
shl edx,5
|
||||
add eax,edx
|
||||
cmp eax,edi
|
||||
jne npc_move_done
|
||||
; Integer cell membership is insufficient: finish at the exact cell centre.
|
||||
mov eax,edi
|
||||
and eax,31
|
||||
shl eax,16
|
||||
add eax,FP_HALF
|
||||
cmp eax,[esi].NpcMindEntity.posX
|
||||
jne npc_move_done
|
||||
mov eax,edi
|
||||
shr eax,5
|
||||
shl eax,16
|
||||
add eax,FP_HALF
|
||||
cmp eax,[esi].NpcMindEntity.posY
|
||||
jne npc_move_done
|
||||
dec npcLife3D[ebx].pathCount
|
||||
cmp budget,0
|
||||
jne npc_move_cell
|
||||
cmp npcLife3D[ebx].pathCount,0
|
||||
jne npc_move_done
|
||||
npc_move_arrived:
|
||||
mov eax,npcLife3D[ebx].destination
|
||||
mov npcLife3D[ebx].state,NPC_STAND
|
||||
mov npcLife3D[ebx].remaining,3500
|
||||
cmp eax,0
|
||||
jne @F
|
||||
mov npcLife3D[ebx].state,NPC_AWAY
|
||||
mov npcLife3D[ebx].remaining,4500
|
||||
jmp npc_move_done
|
||||
@@:
|
||||
cmp eax,7
|
||||
je @F
|
||||
cmp eax,8
|
||||
jne npc_move_done
|
||||
@@:
|
||||
mov npcLife3D[ebx].state,NPC_SIT
|
||||
mov npcLife3D[ebx].remaining,12000
|
||||
jmp npc_move_done
|
||||
npc_move_blocked:
|
||||
mov npcLife3D[ebx].state,NPC_STAND
|
||||
mov npcLife3D[ebx].remaining,1000
|
||||
mov npcLife3D[ebx].pathCount,0
|
||||
npc_move_done:
|
||||
ret
|
||||
NpcMove3D ENDP
|
||||
|
||||
UpdateNpcLife3D PROC uses ebx esi edi
|
||||
local milliseconds:DWORD,destination:DWORD
|
||||
cmp npcLifeReady3D,1
|
||||
jne npc_update_done
|
||||
cmp hallLevel3D,0
|
||||
jne npc_update_done
|
||||
mov eax,deltaTime3D
|
||||
cmp eax,250
|
||||
jbe @F
|
||||
mov eax,250
|
||||
@@:
|
||||
mov milliseconds,eax
|
||||
add npcLifeClock3D,eax
|
||||
xor esi,esi
|
||||
npc_update_person:
|
||||
imul ebx,esi,SIZEOF NpcLife3D
|
||||
mov eax,milliseconds
|
||||
add npcLife3D[ebx].poseClock,eax
|
||||
cmp npcLife3D[ebx].state,NPC_WALK
|
||||
jne npc_update_wait
|
||||
invoke NpcMove3D,esi,milliseconds
|
||||
jmp npc_update_sync
|
||||
npc_update_wait:
|
||||
sub npcLife3D[ebx].remaining,eax
|
||||
ja npc_update_sync
|
||||
cmp npcLife3D[ebx].state,NPC_AWAY
|
||||
jne npc_update_choose
|
||||
mov eax,npcLife3D[ebx].identity
|
||||
add eax,6
|
||||
cmp eax,NPC_IDENTITY_COUNT
|
||||
jb @F
|
||||
sub eax,NPC_IDENTITY_COUNT
|
||||
@@:
|
||||
mov npcLife3D[ebx].identity,eax
|
||||
mov npcLife3D[ebx].state,NPC_STAND
|
||||
npc_update_choose:
|
||||
mov eax,npcLife3D[ebx].routeStep
|
||||
xor edx,edx
|
||||
mov ecx,NPC_DEST_COUNT
|
||||
div ecx
|
||||
mov eax,npcVisitRoute3D[edx*4]
|
||||
mov destination,eax
|
||||
inc npcLife3D[ebx].routeStep
|
||||
invoke NpcPlanPath3D,esi,destination
|
||||
test eax,eax
|
||||
jz npc_update_retry
|
||||
mov npcLife3D[ebx].state,NPC_WALK
|
||||
jmp npc_update_sync
|
||||
npc_update_retry:
|
||||
mov npcLife3D[ebx].state,NPC_STAND
|
||||
mov npcLife3D[ebx].remaining,1000
|
||||
npc_update_sync:
|
||||
imul edi,esi,SIZEOF NpcMindEntity
|
||||
mov eax,npcLife3D[ebx].state
|
||||
mov casinoNpcs3D[edi].state,eax
|
||||
mov eax,npcLife3D[ebx].remaining
|
||||
mov casinoNpcs3D[edi].stateTimer,eax
|
||||
; Keep the old public position array coherent for existing world checks.
|
||||
imul ecx,esi,SIZEOF CityProp3D
|
||||
mov eax,casinoNpcs3D[edi].posX
|
||||
mov hallGuests3D[ecx].posX,eax
|
||||
mov eax,casinoNpcs3D[edi].posY
|
||||
mov hallGuests3D[ecx].posY,eax
|
||||
inc esi
|
||||
cmp esi,NPC_LIFE_COUNT
|
||||
jb npc_update_person
|
||||
npc_update_done:
|
||||
ret
|
||||
UpdateNpcLife3D ENDP
|
||||
|
||||
RenderNpcLife3D PROC uses ebx esi edi
|
||||
cmp npcLifeReady3D,1
|
||||
jne npc_draw_done
|
||||
xor esi,esi
|
||||
npc_draw_depth:
|
||||
imul ebx,esi,SIZEOF NpcMindEntity
|
||||
invoke ProjectCityPoint3D,casinoNpcs3D[ebx].posX,casinoNpcs3D[ebx].posY
|
||||
mov npcDrawDepth3D[esi*4],edx
|
||||
mov npcDrawOrder3D[esi*4],esi
|
||||
inc esi
|
||||
cmp esi,NPC_LIFE_COUNT
|
||||
jb npc_draw_depth
|
||||
xor esi,esi
|
||||
npc_draw_sort:
|
||||
lea edi,[esi+1]
|
||||
npc_draw_compare:
|
||||
mov eax,npcDrawOrder3D[esi*4]
|
||||
mov ebx,npcDrawDepth3D[eax*4]
|
||||
mov ecx,npcDrawOrder3D[edi*4]
|
||||
cmp ebx,npcDrawDepth3D[ecx*4]
|
||||
jge @F
|
||||
mov npcDrawOrder3D[esi*4],ecx
|
||||
mov npcDrawOrder3D[edi*4],eax
|
||||
@@:
|
||||
inc edi
|
||||
cmp edi,NPC_LIFE_COUNT
|
||||
jb npc_draw_compare
|
||||
inc esi
|
||||
cmp esi,NPC_LIFE_COUNT-1
|
||||
jb npc_draw_sort
|
||||
xor esi,esi
|
||||
npc_draw_person:
|
||||
mov eax,npcDrawOrder3D[esi*4]
|
||||
imul ebx,eax,SIZEOF NpcLife3D
|
||||
cmp npcLife3D[ebx].state,NPC_AWAY
|
||||
je npc_draw_next
|
||||
imul edi,eax,SIZEOF NpcMindEntity
|
||||
mov eax,casinoNpcs3D[edi].posX
|
||||
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.frame,0
|
||||
cmp npcLife3D[ebx].identity,11
|
||||
jne @F
|
||||
mov npcSprite3D.frame,4
|
||||
@@:
|
||||
cmp npcLife3D[ebx].state,NPC_SIT
|
||||
jne npc_draw_walk
|
||||
mov npcSprite3D.frame,8
|
||||
cmp npcLife3D[ebx].identity,11
|
||||
jne @F
|
||||
mov npcSprite3D.frame,10
|
||||
@@:
|
||||
mov npcSprite3D.worldW,FP_1*4/5
|
||||
mov npcSprite3D.worldH,FP_1
|
||||
jmp npc_draw_sprite
|
||||
npc_draw_walk:
|
||||
cmp npcLife3D[ebx].state,NPC_WALK
|
||||
jne npc_draw_sprite
|
||||
mov eax,npcLife3D[ebx].poseClock
|
||||
xor edx,edx
|
||||
mov ecx,180
|
||||
div ecx
|
||||
and eax,3
|
||||
add npcSprite3D.frame,eax
|
||||
npc_draw_sprite:
|
||||
invoke DrawCityObject3D,OFFSET npcSprite3D,0
|
||||
npc_draw_next:
|
||||
inc esi
|
||||
cmp esi,NPC_LIFE_COUNT
|
||||
jb npc_draw_person
|
||||
npc_draw_done:
|
||||
ret
|
||||
RenderNpcLife3D ENDP
|
||||
|
||||
CheckNpcInteractions3D PROC uses ebx esi edi
|
||||
local distance:DWORD,nearest:DWORD,deltaX:DWORD,deltaY:DWORD
|
||||
cmp npcLifeReady3D,1
|
||||
jne npc_interact_done
|
||||
cmp hallLevel3D,0
|
||||
jne npc_interact_done
|
||||
cmp interactTargetId,0
|
||||
jne npc_interact_done
|
||||
mov npcSelected3D,-1
|
||||
mov nearest,165000
|
||||
xor esi,esi
|
||||
npc_interact_person:
|
||||
imul ebx,esi,SIZEOF NpcLife3D
|
||||
cmp npcLife3D[ebx].state,NPC_AWAY
|
||||
je npc_interact_next
|
||||
imul edi,esi,SIZEOF NpcMindEntity
|
||||
mov eax,casinoNpcs3D[edi].posX
|
||||
sub eax,playerX
|
||||
sar eax,8
|
||||
mov deltaX,eax
|
||||
imul eax,eax
|
||||
mov distance,eax
|
||||
mov eax,casinoNpcs3D[edi].posY
|
||||
sub eax,playerY
|
||||
sar eax,8
|
||||
mov deltaY,eax
|
||||
imul eax,eax
|
||||
add eax,distance
|
||||
cmp eax,nearest
|
||||
jae npc_interact_next
|
||||
mov distance,eax
|
||||
mov eax,playerDirX
|
||||
sar eax,8
|
||||
imul eax,deltaX
|
||||
mov edx,playerDirY
|
||||
sar edx,8
|
||||
imul edx,deltaY
|
||||
add eax,edx
|
||||
cmp eax,6000
|
||||
jl npc_interact_next
|
||||
; Short, bounded line-of-sight test prevents talking through a wall.
|
||||
mov ebx,1
|
||||
npc_interact_ray:
|
||||
mov eax,deltaX
|
||||
imul eax,ebx
|
||||
shl eax,5
|
||||
add eax,playerX
|
||||
sar eax,16
|
||||
mov edx,deltaY
|
||||
imul edx,ebx
|
||||
shl edx,5
|
||||
add edx,playerY
|
||||
sar edx,16
|
||||
cmp eax,32
|
||||
jae npc_interact_next
|
||||
cmp edx,32
|
||||
jae npc_interact_next
|
||||
shl edx,5
|
||||
add edx,eax
|
||||
mov ecx,worldMap3D
|
||||
cmp BYTE PTR [ecx+edx],0
|
||||
jne npc_interact_next
|
||||
inc ebx
|
||||
cmp ebx,8
|
||||
jb npc_interact_ray
|
||||
mov eax,distance
|
||||
mov nearest,eax
|
||||
mov npcSelected3D,esi
|
||||
npc_interact_next:
|
||||
inc esi
|
||||
cmp esi,NPC_LIFE_COUNT
|
||||
jb npc_interact_person
|
||||
cmp npcSelected3D,-1
|
||||
je npc_interact_done
|
||||
mov interactTargetId,INTERACT_NPC
|
||||
mov interactPromptPtr,OFFSET npcTalkPrompt3D
|
||||
npc_interact_done:
|
||||
ret
|
||||
CheckNpcInteractions3D ENDP
|
||||
140
src_graphics/npc_life_data.inc
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
MODE_NPC_DIALOG equ 20
|
||||
IFDEF CASINO_ACTION_TEST
|
||||
DeleteFileA PROTO :DWORD
|
||||
ENDIF
|
||||
INTERACT_NPC equ 40
|
||||
NPC_LIFE_COUNT equ 6
|
||||
NPC_IDENTITY_COUNT equ 12
|
||||
NPC_DEST_COUNT equ 10
|
||||
NPC_STAND equ 0
|
||||
NPC_WALK equ 1
|
||||
NPC_SIT equ 2
|
||||
NPC_AWAY equ 3
|
||||
NPC_PATH_CAP equ 1024
|
||||
InitNpcLife3D PROTO
|
||||
UpdateNpcLife3D PROTO
|
||||
RenderNpcLife3D PROTO
|
||||
CheckNpcInteractions3D PROTO
|
||||
OpenNpcDialog3D PROTO
|
||||
HandleNpcDialog3D PROTO
|
||||
RenderNpcDialog3D PROTO
|
||||
CloseNpcDialog3D PROTO
|
||||
NpcPlanPath3D PROTO :DWORD,:DWORD
|
||||
NpcTryCell3D PROTO :DWORD,:DWORD
|
||||
NpcMove3D PROTO :DWORD,:DWORD
|
||||
NpcCanStep3D PROTO :DWORD,:DWORD,:DWORD
|
||||
NpcRecordRound3D PROTO :DWORD,:DWORD
|
||||
NpcEnsureJournal3D PROTO
|
||||
NpcSaveJournal3D PROTO
|
||||
NpcAcceptContract3D PROTO :DWORD
|
||||
NpcClaimContract3D PROTO :DWORD
|
||||
NpcContractType3D PROTO :DWORD
|
||||
NpcDate3D PROTO
|
||||
NpcNameText3D PROTO :DWORD
|
||||
NpcLife3D STRUCT
|
||||
identity dd ?
|
||||
state dd ?
|
||||
remaining dd ?
|
||||
destination dd ?
|
||||
routeStep dd ?
|
||||
pathCount dd ?
|
||||
remainder dd ?
|
||||
poseClock dd ?
|
||||
NpcLife3D ENDS
|
||||
.data
|
||||
npcLife3D NpcLife3D NPC_LIFE_COUNT dup(<>)
|
||||
npcLifeReady3D dd 0
|
||||
npcLifeClock3D dd 0
|
||||
npcSelected3D dd -1
|
||||
npcDialogIdentity3D dd 0
|
||||
npcDialogError3D dd 0
|
||||
npcNameBuffer3D db 64 dup(0)
|
||||
npcJournalIoError3D dd 0
|
||||
npcDestX3D dd 16*FP_1+FP_HALF,16*FP_1+FP_HALF,10*FP_1+FP_HALF,6*FP_1+FP_HALF,13*FP_1+FP_HALF
|
||||
dd 21*FP_1+FP_HALF,7*FP_1+FP_HALF,6*FP_1+FP_HALF,16*FP_1+FP_HALF,16*FP_1+FP_HALF
|
||||
npcDestY3D dd 28*FP_1+FP_HALF,17*FP_1+FP_HALF,13*FP_1+FP_HALF,14*FP_1+FP_HALF,9*FP_1+FP_HALF
|
||||
dd 10*FP_1+FP_HALF,25*FP_1+FP_HALF,27*FP_1+FP_HALF,10*FP_1+FP_HALF,7*FP_1+FP_HALF
|
||||
npcVisitRoute3D dd 1,5,8,2,3,6,7,9,1,0
|
||||
npcStartDest3D dd 1,2,3,6,8,7
|
||||
npcSprite3D CityProp3D <0,0,FP_1*3/5,FP_1*6/5,0,OFFSET hallPatrons3D>
|
||||
npcDrawOrder3D dd NPC_LIFE_COUNT dup(0)
|
||||
npcDrawDepth3D dd NPC_LIFE_COUNT dup(0)
|
||||
npcJournalLoaded3D dd 0
|
||||
npcJournalPath3D db 260 dup(0)
|
||||
npcJournalNextPath3D db 260 dup(0)
|
||||
npcJournalSuffix3D db ".npc",0
|
||||
IFDEF CASINO_ACTION_TEST
|
||||
npcJournalBasePtr3D dd OFFSET npcJournalTestBase3D
|
||||
npcJournalTestBase3D db "build\arrival\fixtures\npc-default.dat",0
|
||||
ELSE
|
||||
npcJournalBasePtr3D dd 0
|
||||
ENDIF
|
||||
npcDateOverride3D dd 0
|
||||
npcSystemTime3D dw 8 dup(0)
|
||||
; One bounded journal per profile; visitors 0..5 and 6..11 alternate at the entrance.
|
||||
npcJournal3D LABEL DWORD
|
||||
npcJournalMagic3D dd 3151504Eh
|
||||
npcJournalDay3D dd 0
|
||||
npcAccepted3D dd 0
|
||||
npcClaimed3D dd 0
|
||||
npcProgress3D dd NPC_IDENTITY_COUNT dup(0)
|
||||
npcJournalChecksum3D dd 0
|
||||
NPC_JOURNAL_SIZE equ $-npcJournal3D
|
||||
npcJournalRead3D db NPC_JOURNAL_SIZE dup(0)
|
||||
npcQuestGames3D dd -1,0,0,1,1,2,2,3,3,4,5,5
|
||||
npcQuestWins3D dd 0,0,1,0,1,0,1,0,1,0,0,1
|
||||
npcQuestGoals3D dd 3,3,1,2,1,2,1,3,1,3,1,1
|
||||
npcQuestRewards3D dd 150,150,350,250,500,350,700,250,500,150,300,700
|
||||
npcQuestTexts3D dd OFFSET npcQuest0,OFFSET npcQuest1,OFFSET npcQuest2,OFFSET npcQuest3
|
||||
dd OFFSET npcQuest4,OFFSET npcQuest5,OFFSET npcQuest6,OFFSET npcQuest7
|
||||
dd OFFSET npcQuest8,OFFSET npcQuest9,OFFSET npcQuest10,OFFSET npcQuest11
|
||||
npcNames3D dd OFFSET npcName0,OFFSET npcName1,OFFSET npcName2,OFFSET npcName3,OFFSET npcName4,OFFSET npcName5
|
||||
dd OFFSET npcName6,OFFSET npcName7,OFFSET npcName8,OFFSET npcName9,OFFSET npcName10,OFFSET npcName11
|
||||
npcGreetings3D dd OFFSET npcGreeting0,OFFSET npcGreeting1,OFFSET npcGreeting2
|
||||
dd OFFSET npcGreeting3,OFFSET npcGreeting4,OFFSET npcGreeting5
|
||||
npcName6 db 196,236,232,242,240,232,233,32,209,229,240,238,226,0
|
||||
npcName7 db 194,232,234,242,238,240,32,195,240,238,236,238,226,0
|
||||
npcName8 db 195,240,232,227,238,240,232,233,32,203,232,241,0
|
||||
npcName9 db 207,224,226,229,235,32,204,232,240,237,251,233,0
|
||||
npcName10 db 192,237,242,238,237,32,193,238,227,224,242,251,233,0
|
||||
npcName11 db 192,235,232,241,224,32,194,229,242,240,238,226,224,0
|
||||
npcGreeting0 db 207,240,238,226,229,240,232,236,32,242,226,238,254,32,226,251,228,229,240,230,234,243,63,0
|
||||
npcGreeting1 db 209,229,227,238,228,237,255,32,255,32,232,227,240,224,254,32,241,236,229,235,238,46,0
|
||||
npcGreeting2 db 211,228,224,247,224,32,235,254,225,232,242,32,242,229,240,239,229,235,232,226,251,245,46,0
|
||||
npcGreeting3 db 196,224,226,224,233,32,241,251,227,240,224,229,236,32,225,229,231,32,241,239,229,248,234,232,46,0
|
||||
npcGreeting4 db 197,241,242,252,32,228,229,235,238,32,241,32,237,224,227,240,224,228,238,233,46,0
|
||||
npcGreeting5 db 207,238,239,240,238,225,243,229,236,32,241,226,238,232,32,241,232,235,251,63,0
|
||||
npcQuest0 db 199,224,226,229,240,248,232,32,235,254,225,251,229,32,51,32,240,224,243,237,228,224,0
|
||||
npcQuest1 db 207,238,228,225,240,238,241,252,32,236,238,237,229,242,234,243,32,51,32,240,224,231,224,0
|
||||
npcQuest2 db 194,251,232,227,240,224,233,32,226,32,236,238,237,229,242,234,243,0
|
||||
npcQuest3 db 209,251,227,240,224,233,32,50,32,240,224,243,237,228,224,32,226,32,225,235,253,234,228,230,229,234,0
|
||||
npcQuest4 db 194,251,232,227,240,224,233,32,226,32,225,235,253,234,228,230,229,234,0
|
||||
npcQuest5 db 199,224,226,229,240,248,232,32,50,32,240,224,231,228,224,247,232,32,239,238,234,229,240,224,0
|
||||
npcQuest6 db 194,251,232,227,240,224,233,32,240,224,231,228,224,247,243,32,239,238,234,229,240,224,0
|
||||
npcQuest7 db 209,251,227,240,224,233,32,51,32,240,224,243,237,228,224,32,226,32,240,243,235,229,242,234,243,0
|
||||
npcQuest8 db 194,251,232,227,240,224,233,32,226,32,240,243,235,229,242,234,243,0
|
||||
npcQuest9 db 202,240,243,242,232,32,224,226,242,238,236,224,242,32,51,32,240,224,231,224,0
|
||||
npcQuest10 db 199,224,226,229,240,248,232,32,239,224,240,242,232,254,32,226,32,228,243,240,224,234,224,0
|
||||
npcQuest11 db 194,251,232,227,240,224,233,32,239,224,240,242,232,254,32,226,32,228,243,240,224,234,224,0
|
||||
npcTalkPrompt3D db 91,69,93,32,207,206,195,206,194,206,208,200,210,220,0
|
||||
npcContractTitle3D db 215,197,203,203,197,205,196,198,32,205,192,32,209,197,195,206,196,205,223,0
|
||||
npcProgressText3D db 207,240,238,227,240,229,241,241,0
|
||||
npcRewardText3D db 205,224,227,240,224,228,224,0
|
||||
npcAcceptText3D db 194,199,223,210,220,0
|
||||
npcClaimText3D db 205,192,195,208,192,196,192,0
|
||||
npcCloseText3D db 199,192,202,208,219,210,220,0
|
||||
npcAvailableText3D db 204,238,230,237,238,32,239,240,232,237,255,242,252,0
|
||||
npcActiveText3D db 194,251,239,238,235,237,255,229,242,241,255,0
|
||||
npcReadyText3D db 195,238,242,238,226,238,33,32,199,224,225,229,240,232,32,237,224,227,240,224,228,243,0
|
||||
npcDoneText3D db 205,224,227,240,224,228,224,32,243,230,229,32,239,238,235,243,247,229,237,224,0
|
||||
npcIoErrorText3D db 205,229,32,243,228,224,235,238,241,252,32,241,238,245,240,224,237,232,242,252,32,231,224,228,224,237,232,229,0
|
||||
npcSlashText3D db " / ",0
|
||||
.data?
|
||||
npcPaths3D dd NPC_LIFE_COUNT*NPC_PATH_CAP dup(?)
|
||||
npcParents3D dd NPC_PATH_CAP dup(?)
|
||||
npcQueue3D dd NPC_PATH_CAP dup(?)
|
||||
.data
|
||||
npcSearchHead3D dd 0
|
||||
npcSearchTail3D dd 0
|
||||
npcSearchGoal3D dd 0
|
||||
.code
|
||||
1005
src_graphics/npc_mind.inc
Normal file
258
src_graphics/npc_mind_data.inc
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
; ==============================================================================
|
||||
; NPC MIND DATA - MASM32 / CP1251
|
||||
; Multi-agent AI: Open-space Navigation, Personalities & Multi-seat Poker
|
||||
; ==============================================================================
|
||||
|
||||
NPCAI_ARCHETYPE_SHARK equ 0 ; Акула (Tight-Aggressive)
|
||||
NPCAI_ARCHETYPE_MANIAC equ 1 ; Лудоман (Loose-Aggressive)
|
||||
NPCAI_ARCHETYPE_ROCK equ 2 ; Скала (Tight-Passive)
|
||||
NPCAI_ARCHETYPE_CALLING_STATION equ 3 ; Автоответчик (Loose-Passive)
|
||||
NPCAI_ARCHETYPE_WHALE equ 4 ; Мажор (Высокий банкролл, хаос)
|
||||
NPCAI_ARCHETYPE_ROOKIE equ 5 ; Новичок (Ошибки, неуверенность)
|
||||
|
||||
NPCAI_STATE_IDLE equ 0 ; Стоит, осматривается
|
||||
NPCAI_STATE_WALK equ 1 ; Идет по вейпоинтам
|
||||
NPCAI_STATE_GAMBLE equ 2 ; Играет за столом
|
||||
NPCAI_STATE_BAR equ 3 ; У бара
|
||||
NPCAI_STATE_ATM equ 4 ; У банкомата
|
||||
NPCAI_STATE_STAGE equ 5 ; Смотрит шоу
|
||||
|
||||
MPK_SEAT_EMPTY equ 0
|
||||
MPK_SEAT_ACTIVE equ 1
|
||||
MPK_SEAT_FOLDED equ 2
|
||||
MPK_SEAT_ALLIN equ 3
|
||||
MPK_SEAT_BUST equ 4
|
||||
|
||||
MPK_ACT_NONE equ 0
|
||||
MPK_ACT_FOLD equ 1
|
||||
MPK_ACT_CHECK equ 2
|
||||
MPK_ACT_CALL equ 3
|
||||
MPK_ACT_RAISE equ 4
|
||||
MPK_ACT_ALLIN equ 5
|
||||
|
||||
MPK_STAGE_PREFLOP equ 0
|
||||
MPK_STAGE_FLOP equ 1
|
||||
MPK_STAGE_TURN equ 2
|
||||
MPK_STAGE_RIVER equ 3
|
||||
MPK_STAGE_SHOWDOWN equ 4
|
||||
|
||||
NPCAI_MAX_NPCS equ 6
|
||||
MPK_MAX_SEATS equ 4
|
||||
NPCAI_WAYPOINT_COUNT equ 16
|
||||
|
||||
; ------------------------------------------------------------------------------
|
||||
; Структуры данных
|
||||
; ------------------------------------------------------------------------------
|
||||
|
||||
NpcPersonality STRUCT
|
||||
namePtr dd ?
|
||||
titlePtr dd ?
|
||||
archetypeId dd ?
|
||||
baseAggression dd ? ; 0..100
|
||||
baseTightness dd ? ; 0..100
|
||||
baseBluffRate dd ? ; 0..100
|
||||
baseCourage dd ? ; 0..100
|
||||
tiltSens dd ? ; 0..100
|
||||
defaultBank dd ?
|
||||
phraseWinPtr dd ?
|
||||
phraseLosePtr dd ?
|
||||
phraseBluffPtr dd ?
|
||||
phraseBustPtr dd ?
|
||||
NpcPersonality ENDS
|
||||
|
||||
NpcMindEntity STRUCT
|
||||
posX dd ? ; 16.16 FP
|
||||
posY dd ? ; 16.16 FP
|
||||
dirX dd ? ; 16.16 FP
|
||||
dirY dd ? ; 16.16 FP
|
||||
speed dd ? ; 16.16 FP
|
||||
state dd ? ; NPCAI_STATE_*
|
||||
stateTimer dd ?
|
||||
currentNode dd ?
|
||||
targetNode dd ?
|
||||
profileId dd ?
|
||||
currentChips dd ?
|
||||
currentTilt dd ? ; 0..100
|
||||
thoughtPtr dd ?
|
||||
reactionPtr dd ?
|
||||
NpcMindEntity ENDS
|
||||
|
||||
MpkSeat STRUCT
|
||||
isHuman dd ? ; 1=Player, 0=NPC
|
||||
profileId dd ? ; Индекс NpcPersonality (0..5)
|
||||
chips dd ?
|
||||
roundBet dd ?
|
||||
totalBet dd ?
|
||||
card1 dd ?
|
||||
card2 dd ?
|
||||
evalScore dd ?
|
||||
seatStatus dd ? ; MPK_SEAT_*
|
||||
lastAction dd ? ; MPK_ACT_*
|
||||
lastRaiseAmount dd ?
|
||||
thoughtPtr dd ?
|
||||
reactionPtr dd ?
|
||||
MpkSeat ENDS
|
||||
|
||||
MultiPokerTable STRUCT
|
||||
seats MpkSeat MPK_MAX_SEATS dup(<>)
|
||||
commCards dd 5 dup(?)
|
||||
commCount dd ?
|
||||
mainPot dd ?
|
||||
currentHighBet dd ?
|
||||
minRaise dd ?
|
||||
dealerButton dd ?
|
||||
currentTurn dd ?
|
||||
activeSeats dd ?
|
||||
smallBlind dd ?
|
||||
bigBlind dd ?
|
||||
stage dd ?
|
||||
MultiPokerTable ENDS
|
||||
|
||||
NpcWaypoint STRUCT
|
||||
posX dd ? ; 16.16 FP
|
||||
posY dd ? ; 16.16 FP
|
||||
neighbor0 dd ?
|
||||
neighbor1 dd ?
|
||||
neighbor2 dd ?
|
||||
neighbor3 dd ?
|
||||
zoneType dd ?
|
||||
NpcWaypoint ENDS
|
||||
|
||||
; ------------------------------------------------------------------------------
|
||||
; Строковые константы и описания (CP1251)
|
||||
; ------------------------------------------------------------------------------
|
||||
|
||||
.data
|
||||
|
||||
; Имена и титулы 6 уникальных персонажей
|
||||
npcName0 db "Виктор «Акула»",0
|
||||
npcTitle0 db "Профессионал (Tight-Aggressive)",0
|
||||
|
||||
npcName1 db "Сергей «Лудоман»",0
|
||||
npcTitle1 db "Маньяк (Loose-Aggressive, ТИЛЬТ)",0
|
||||
|
||||
npcName2 db "Дядя Толя «Скала»",0
|
||||
npcTitle2 db "Ветеран (Tight-Passive)",0
|
||||
|
||||
npcName3 db "Степан «Автоответчик»",0
|
||||
npcTitle3 db "Любитель (Calling Station)",0
|
||||
|
||||
npcName4 db "Мажор Артём",0
|
||||
npcTitle4 db "Хайроллер (Whale, Безумные ставки)",0
|
||||
|
||||
npcName5 db "Влад «Новичок»",0
|
||||
npcTitle5 db "Студент (Rookie, Неопытный)",0
|
||||
|
||||
; Фразы победы
|
||||
npcWin0 db "«Холодный расчет и никакой магии. Банк мой.»",0
|
||||
npcWin1 db "«ХА-ХА! Кто тут король казино?! Все фишки сюда!»",0
|
||||
npcWin2 db "«Тише едешь — дальше будешь, молодежь.»",0
|
||||
npcWin3 db "«Опа, закрылся стрит! А вы не верили!»",0
|
||||
npcWin4 db "«Официант, всем шампанского за мой счет!»",0
|
||||
npcWin5 db "«Ого! Неужели я правда победил?! Вот это да!»",0
|
||||
|
||||
; Фразы поражения / бэдбита
|
||||
npcLose0 db "«Бывает. Математическая дисперсия на дистанции вернет всё.»",0
|
||||
npcLose1 db "«ДА КАК ТАК-ТО?! Опять ривером переехали, сука!»",0
|
||||
npcLose2 db "«Знал ведь, что надо было сбрасывать еще на флопе...»",0
|
||||
npcLose3 db "«Эх, чутка не хватило до флеша... в следующий раз повезет.»",0
|
||||
npcLose4 db "«Пф-ф, копейки. Сейчас сниму еще пачку в банкомате.»",0
|
||||
npcLose5 db "«Я так и знал... Надо было внимательнее читать правила.»",0
|
||||
|
||||
; Фразы блефа / рейза
|
||||
npcBluff0 db "«Твоя рука слабее. Сэкономь фишки и пасуй.»",0
|
||||
npcBluff1 db "«Слабаки! Вам не по карману этот банк, двигайте пас!»",0
|
||||
npcBluff2 db "«У меня отличная карта. Не советую лезть под колеса.»",0
|
||||
npcBluff3 db "«А я просто хочу посмотреть следующую карту!»",0
|
||||
npcBluff4 db "«Вы ставите копейки! Давайте играть по-взрослому!»",0
|
||||
npcBluff5 db "«Э-э... кажется, я поднимаю ставку. Вы со мной?»",0
|
||||
|
||||
; Фразы банкротства
|
||||
npcBust0 db "«Лимит на сегодня исчерпан. Пора делать паузу.»",0
|
||||
npcBust1 db "«Всё в ноль! Бегу к банкомату, я обязан отыграться!»",0
|
||||
npcBust2 db "«Пенсия кончилась... Пойду подышу на свежем воздухе.»",0
|
||||
npcBust3 db "«Ой, фишки кончились... Пойду в бар за пивом.»",0
|
||||
npcBust4 db "«Опять обнулился? Ерунда, сейчас сниму еще $50,000.»",0
|
||||
npcBust5 db "«Кажется, на метро мне уже не хватает...»",0
|
||||
|
||||
; Мысли в свободном перемещении по казино
|
||||
thWalkWander db "Осматривает игровой зал в поисках интересной игры",0
|
||||
thWalkTable db "Направляется к покерному столу испытать удачу",0
|
||||
thWalkBar db "Решил заглянуть в бар за напитком",0
|
||||
thWalkAtm db "Закончились фишки, направляется к банкомату",0
|
||||
thWalkStage db "Подходит к сцене посмотреть на танцовщиц",0
|
||||
thIdleBored db "Стоит у колонны, подсчитывает оставшиеся деньги",0
|
||||
|
||||
; Мысли за покерным столом
|
||||
thEvalStrong db "Чувствует натс! Готовит ловушку для оппонентов.",0
|
||||
thEvalGood db "Рука сильная, отличные шансы забрать этот банк.",0
|
||||
thEvalDraw db "Считает ауты: шансы банка выгодны для колла.",0
|
||||
thEvalTrash db "Карты — мусор. Смысла рисковать фишками нет.",0
|
||||
thEvalTilted db "[ТИЛЬТ!] Злится после проигрыша и идет на таран!",0
|
||||
thEvalBluffing db "БЛЕФ! Изображает монстра и давит ставкой!",0
|
||||
|
||||
; Описания действий
|
||||
thActFold db "Сбрасывает карты в пас",0
|
||||
thActCheck db "Чекает, пропуская ход",0
|
||||
thActCall db "Коллирует (уравнивает) текущую ставку",0
|
||||
thActRaise db "Повышает ставку (рейз!)",0
|
||||
thActAllIn db "Двигает все фишки вперед — ВА-БАНК (ОЛЛ-ИН)!",0
|
||||
|
||||
; Названия улиц покера
|
||||
strStagePreflop db "Префлоп (Карманные карты)",0
|
||||
strStageFlop db "Флоп (3 карты стола)",0
|
||||
strStageTurn db "Терн (4 карты стола)",0
|
||||
strStageRiver db "Ривер (5 карт стола)",0
|
||||
strStageShow db "Вскрытие карт (Showdown)",0
|
||||
|
||||
; Тексты интерфейса мульти-покера
|
||||
mpkTitleStr db "=== ТЕХАССКИЙ ХОЛДЕМ: СТОЛ НА 4 ИГРОКА ===",13,10,0
|
||||
mpkPotStr db "Банк стола: $",0
|
||||
mpkStreetStr db " | Раунд: ",0
|
||||
mpkCommCardsStr db "Общие карты на столе: ",0
|
||||
mpkPromptStr db "Ваш ход: [1] Чек/Колл | [2] Рейз | [0] Пас -> ",0
|
||||
mpkWaitNextStr db 13,10,"[Нажмите любую клавишу для следующей раздачи, 0 для выхода]...",0
|
||||
mpkChipsPrefix db " Стек: $",0
|
||||
mpkThoughtPrefix db " [Мысли]: ",0
|
||||
mpkGameOverStr db 13,10,"Раздача окончена. Победитель: ",0
|
||||
mpkWinChipsStr db " выиграл банк $",0
|
||||
|
||||
ALIGN 4
|
||||
|
||||
; База профилей 6 уникальных личностей
|
||||
casinoNpcProfiles NpcPersonality <OFFSET npcName0, OFFSET npcTitle0, NPCAI_ARCHETYPE_SHARK, 75, 85, 20, 85, 15, 5000, OFFSET npcWin0, OFFSET npcLose0, OFFSET npcBluff0, OFFSET npcBust0>
|
||||
NpcPersonality <OFFSET npcName1, OFFSET npcTitle1, NPCAI_ARCHETYPE_MANIAC, 95, 20, 80, 90, 85, 3500, OFFSET npcWin1, OFFSET npcLose1, OFFSET npcBluff1, OFFSET npcBust1>
|
||||
NpcPersonality <OFFSET npcName2, OFFSET npcTitle2, NPCAI_ARCHETYPE_ROCK, 25, 90, 5, 30, 20, 4000, OFFSET npcWin2, OFFSET npcLose2, OFFSET npcBluff2, OFFSET npcBust2>
|
||||
NpcPersonality <OFFSET npcName3, OFFSET npcTitle3, NPCAI_ARCHETYPE_CALLING_STATION, 15, 30, 10, 75, 40, 3000, OFFSET npcWin3, OFFSET npcLose3, OFFSET npcBluff3, OFFSET npcBust3>
|
||||
NpcPersonality <OFFSET npcName4, OFFSET npcTitle4, NPCAI_ARCHETYPE_WHALE, 70, 45, 55, 70, 50, 10000, OFFSET npcWin4, OFFSET npcLose4, OFFSET npcBluff4, OFFSET npcBust4>
|
||||
NpcPersonality <OFFSET npcName5, OFFSET npcTitle5, NPCAI_ARCHETYPE_ROOKIE, 40, 50, 25, 40, 60, 2000, OFFSET npcWin5, OFFSET npcLose5, OFFSET npcBluff5, OFFSET npcBust5>
|
||||
|
||||
; Граф вейпоинтов казино (координаты 16.16 FP и связи)
|
||||
casinoWaypoints3D NpcWaypoint <16*FP_1, 28*FP_1, 1, 4, 8, 0, 0> ; 0: Вход в казино
|
||||
NpcWaypoint <16*FP_1, 20*FP_1, 0, 2, 4, 8, 0> ; 1: Центр холла (юг)
|
||||
NpcWaypoint <16*FP_1, 14*FP_1, 1, 3, 10, 12, 0> ; 2: Центр холла (север)
|
||||
NpcWaypoint <16*FP_1, 6*FP_1, 2, 10, 12, 3, 7> ; 3: Перед сценой танцовщиц
|
||||
NpcWaypoint < 8*FP_1, 20*FP_1, 0, 1, 5, 7, 0> ; 4: Западный коридор
|
||||
NpcWaypoint < 6*FP_1, 14*FP_1, 4, 6, 2, 5, 4> ; 5: Автоматы 777
|
||||
NpcWaypoint < 6*FP_1, 9*FP_1, 5, 10, 2, 6, 4> ; 6: Автоматы CloverPit
|
||||
NpcWaypoint < 4*FP_1, 25*FP_1, 4, 0, 7, 7, 5> ; 7: Барная стойка
|
||||
NpcWaypoint <24*FP_1, 20*FP_1, 0, 1, 9, 14, 0> ; 8: Восточный коридор
|
||||
NpcWaypoint <26*FP_1, 25*FP_1, 8, 0, 9, 9, 0> ; 9: Зона отдыха VIP
|
||||
NpcWaypoint <12*FP_1, 9*FP_1, 2, 3, 6, 11, 2> ; 10: Стол Блэкджека
|
||||
NpcWaypoint <16*FP_1, 11*FP_1, 2, 10, 12, 11, 3> ; 11: Стол Рулетки
|
||||
NpcWaypoint <20*FP_1, 9*FP_1, 2, 3, 11, 13, 1> ; 12: Стол Покера (Холдем)
|
||||
NpcWaypoint <24*FP_1, 9*FP_1, 12, 8, 14, 13, 1> ; 13: Стол Дурака
|
||||
NpcWaypoint <26*FP_1, 15*FP_1, 8, 13, 14, 14, 6> ; 14: Банкомат (ATM)
|
||||
NpcWaypoint <10*FP_1, 15*FP_1, 2, 4, 5, 10, 0> ; 15: Зона костей/черепов
|
||||
|
||||
; 6 активных персонажей, гуляющих по залу казино
|
||||
casinoNpcs3D NpcMindEntity NPCAI_MAX_NPCS dup(<>)
|
||||
|
||||
; Экземпляр стола мульти-покера
|
||||
multiPokerTable MultiPokerTable <>
|
||||
|
||||
; Колода и рабочий буфер для мульти-покера
|
||||
multiDeck dd 52 dup(0)
|
||||
multiDeckIndex dd 0
|
||||
multiEvalHand dd 7 dup(0)
|
||||
multiActionWait dd 0
|
||||
|
|
@ -8,6 +8,12 @@ WindowEvents3D PROC uses ebx esi edi hwnd:DWORD, uMsg:DWORD, wp:DWORD, lp:DWORD
|
|||
@@:
|
||||
cmp uMsg, 201h
|
||||
je event_mouse_down
|
||||
cmp uMsg,203h
|
||||
jne @F
|
||||
cmp engineMode,MODE_POOL
|
||||
je event_mouse_down
|
||||
jmp event_default
|
||||
@@:
|
||||
cmp uMsg, 200h
|
||||
jne @F
|
||||
cmp engineMode, MODE_POOL
|
||||
|
|
@ -61,9 +67,18 @@ event_mouse_down:
|
|||
mov mouseY3D, eax
|
||||
cmp uMsg,200h
|
||||
jne @F
|
||||
cmp eax,50
|
||||
jb event_done
|
||||
cmp eax,211
|
||||
jae event_done
|
||||
@@:
|
||||
cmp uMsg,203h
|
||||
je pyr_event_pick
|
||||
mov pyrPickClick3D,0
|
||||
jmp pyr_event_pick_done
|
||||
pyr_event_pick:
|
||||
mov pyrPickClick3D,1
|
||||
pyr_event_pick_done:
|
||||
mov mouseClick3D, 1
|
||||
jmp event_done
|
||||
event_key_down:
|
||||
|
|
|
|||
71
src_graphics/pyramid_data.inc
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
InitPyramidState3D PROTO
|
||||
PyramidContact3D PROTO :DWORD,:DWORD
|
||||
PyramidContactEnd3D PROTO :DWORD,:DWORD
|
||||
PyramidCross3D PROTO :DWORD
|
||||
PyramidRail3D PROTO :DWORD,:DWORD
|
||||
PyramidDistance3D PROTO :DWORD,:DWORD
|
||||
PyramidDirection3D PROTO
|
||||
PyramidSelect3D PROTO :DWORD
|
||||
PyramidCanPlace3D PROTO :DWORD,:DWORD,:DWORD
|
||||
PyramidRespot3D PROTO :DWORD
|
||||
PyramidPenalty3D PROTO :DWORD
|
||||
PyramidChoice3D PROTO :DWORD
|
||||
PyramidRack3D PROTO
|
||||
PyramidPick3D PROTO :DWORD,:DWORD
|
||||
PyramidPathClear3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
PyramidGuide3D PROTO
|
||||
PyramidBall3D PROTO :DWORD,:DWORD,:DWORD,:DWORD
|
||||
FreePyramidAssets3D PROTO
|
||||
.data
|
||||
pyrTablePack3D AnimPack3D <>
|
||||
pyrBallsPack3D AnimPack3D <>
|
||||
pyrTablePath3D db "assets\animations\pyramid\table-v2.bin",0
|
||||
pyrBallsPath3D db "assets\animations\pyramid\balls-v1.bin",0
|
||||
pyrCue3D dd 0
|
||||
pyrScore3D dd 0,0
|
||||
pyrOwner3D dd 16 dup(-1)
|
||||
pyrRoll3D dd 16 dup(0)
|
||||
pyrPreviousX3D dd 16 dup(0)
|
||||
pyrHistoryRails3D dd 16 dup(0)
|
||||
pyrHistoryCross3D dd 16 dup(0)
|
||||
pyrRailHalf3D dd 16 dup(0)
|
||||
pyrTouched3D dd 0
|
||||
pyrValidEnd3D dd 0
|
||||
pyrRailSide3D dd 0
|
||||
pyrFoulReason3D dd 0
|
||||
pyrIllegalBreak3D dd 0
|
||||
pyrFine3D dd 0
|
||||
pyrFineActive3D dd 0
|
||||
pyrAimCarry3D dd 0
|
||||
pyrPickClick3D dd 0
|
||||
pyrDirX3D dd FP_1
|
||||
pyrDirY3D dd 0
|
||||
pyrAimFactor3D REAL8 651.8986469044033
|
||||
pyrGuideOn3D dd 1
|
||||
pyrTarget3D dd -1
|
||||
pyrGuideX3D dd 0
|
||||
pyrGuideY3D dd 0
|
||||
pyrChoiceActor3D dd 0
|
||||
pyrFouler3D dd 0
|
||||
pyrSettled3D dd 0
|
||||
pyrExit3D db 194,32,213,206,203,203,0
|
||||
pyrTitle3D db 207,200,208,192,204,200,196,192,0
|
||||
pyrBreakText3D db 208,192,199,193,200,210,200,197,0
|
||||
pyrTurnText3D db 213,206,196,0
|
||||
pyrCueText3D db 193,200,210,206,202,0
|
||||
pyrGuideText3D db 207,208,200,214,197,203,0
|
||||
pyrPenaltyText3D db 216,210,208,192,212,205,206,201,32,216,192,208,0
|
||||
pyrChoiceText3D db 207,206,209,203,197,32,216,210,208,192,212,192,0
|
||||
pyrPlayText3D db 200,195,208,192,210,220,0
|
||||
pyrPassText3D db 207,197,208,197,196,192,210,220,0
|
||||
pyrRackText3D db 207,197,208,197,193,200,210,220,0
|
||||
pyrTheirBreakText3D db 197,195,206,32,211,196,192,208,0
|
||||
pyrNoContactText3D db 205,197,210,32,202,192,209,192,205,200,223,0
|
||||
pyrBadBreakText3D db 205,197,194,197,208,205,219,201,32,208,192,199,193,206,201,0
|
||||
pyrBadEndText3D db 205,197,194,197,208,205,219,201,32,211,196,192,208,0
|
||||
pyrPlayerName3D db 194,219,0
|
||||
pyrAIName3D db 200,200,0
|
||||
pyrSkipText3D db 207,208,206,207,211,209,202,0
|
||||
pyrScoreSep3D db ":",0
|
||||
pyrStatusNames3D dd OFFSET pyrTurnText3D,OFFSET pyrNoContactText3D,OFFSET pyrBadBreakText3D,OFFSET pyrBadEndText3D
|
||||
.code
|
||||
688
src_graphics/pyramid_play.inc
Normal file
|
|
@ -0,0 +1,688 @@
|
|||
PyramidSelect3D PROC uses ebx ball:DWORD
|
||||
cmp poolBreak3D,0
|
||||
je @F
|
||||
mov pyrCue3D,0
|
||||
ret
|
||||
@@:
|
||||
mov ebx,ball
|
||||
cmp ebx,15
|
||||
ja pyr_select_default
|
||||
cmp poolActive3D[ebx*4],1
|
||||
jne pyr_select_default
|
||||
mov pyrCue3D,ebx
|
||||
mov poolCalled3D,ebx
|
||||
ret
|
||||
pyr_select_default:
|
||||
mov ebx,pyrCue3D
|
||||
cmp poolActive3D[ebx*4],1
|
||||
je pyr_select_done
|
||||
xor ebx,ebx
|
||||
pyr_select_scan:
|
||||
cmp poolActive3D[ebx*4],1
|
||||
je pyr_select_found
|
||||
inc ebx
|
||||
cmp ebx,16
|
||||
jb pyr_select_scan
|
||||
ret
|
||||
pyr_select_found:
|
||||
mov pyrCue3D,ebx
|
||||
mov poolCalled3D,ebx
|
||||
pyr_select_done:
|
||||
ret
|
||||
PyramidSelect3D ENDP
|
||||
|
||||
PyramidPick3D PROC uses ebx esi px:DWORD,py:DWORD
|
||||
xor esi,esi
|
||||
pyr_pick_ball:
|
||||
cmp poolActive3D[esi*4],1
|
||||
jne pyr_pick_next
|
||||
mov eax,px
|
||||
sub eax,poolX3D[esi*4]
|
||||
sar eax,12
|
||||
imul eax,eax
|
||||
mov ebx,eax
|
||||
mov eax,py
|
||||
sub eax,poolY3D[esi*4]
|
||||
sar eax,12
|
||||
imul eax,eax
|
||||
add eax,ebx
|
||||
cmp eax,36*16*16
|
||||
ja pyr_pick_next
|
||||
mov eax,esi
|
||||
ret
|
||||
pyr_pick_next:
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_pick_ball
|
||||
mov eax,-1
|
||||
ret
|
||||
PyramidPick3D ENDP
|
||||
|
||||
PyramidDirection3D PROC uses ebx esi
|
||||
mov ecx,poolAngle3D
|
||||
and ecx,511
|
||||
cmp pyrFineActive3D,0
|
||||
jne pyr_direction_fine
|
||||
mov eax,tableCos[ecx*4]
|
||||
mov pyrDirX3D,eax
|
||||
mov eax,tableSin[ecx*4]
|
||||
mov pyrDirY3D,eax
|
||||
ret
|
||||
pyr_direction_fine:
|
||||
mov ecx,pyrFine3D
|
||||
and ecx,4095
|
||||
mov ebx,ecx
|
||||
and ebx,7
|
||||
shr ecx,3
|
||||
lea esi,[ecx+1]
|
||||
and esi,511
|
||||
mov eax,tableCos[esi*4]
|
||||
sub eax,tableCos[ecx*4]
|
||||
imul eax,ebx
|
||||
sar eax,3
|
||||
add eax,tableCos[ecx*4]
|
||||
mov pyrDirX3D,eax
|
||||
mov eax,tableSin[esi*4]
|
||||
sub eax,tableSin[ecx*4]
|
||||
imul eax,ebx
|
||||
sar eax,3
|
||||
add eax,tableSin[ecx*4]
|
||||
mov pyrDirY3D,eax
|
||||
ret
|
||||
PyramidDirection3D ENDP
|
||||
|
||||
PoolAimPoint3D PROC uses ebx px:DWORD,py:DWORD
|
||||
local deltaX:DWORD,deltaY:DWORD,phase:DWORD
|
||||
mov ebx,pyrCue3D
|
||||
mov eax,px
|
||||
sub eax,poolX3D[ebx*4]
|
||||
mov deltaX,eax
|
||||
mov ecx,py
|
||||
sub ecx,poolY3D[ebx*4]
|
||||
mov deltaY,ecx
|
||||
or eax,ecx
|
||||
jz pyr_aim_done
|
||||
fild deltaY
|
||||
fild deltaX
|
||||
fpatan
|
||||
fmul pyrAimFactor3D
|
||||
fistp phase
|
||||
mov eax,phase
|
||||
and eax,4095
|
||||
mov pyrFine3D,eax
|
||||
mov pyrFineActive3D,1
|
||||
call PyramidDirection3D
|
||||
pyr_aim_done:
|
||||
ret
|
||||
PoolAimPoint3D ENDP
|
||||
|
||||
PoolShoot3D PROC uses ebx esi
|
||||
cmp poolState3D,POOL_AIM
|
||||
jne pyr_shoot_done
|
||||
mov ebx,pyrCue3D
|
||||
cmp ebx,15
|
||||
ja pyr_shoot_done
|
||||
cmp poolActive3D[ebx*4],1
|
||||
jne pyr_shoot_done
|
||||
cmp pyrTablePack3D.pixels,0
|
||||
je pyr_shoot_done
|
||||
cmp pyrBallsPack3D.pixels,0
|
||||
je pyr_shoot_done
|
||||
cmp poolBreak3D,0
|
||||
je @F
|
||||
test ebx,ebx
|
||||
jnz pyr_shoot_done
|
||||
cmp poolX3D,95*FP_1
|
||||
jge pyr_shoot_done
|
||||
@@:
|
||||
mov poolFirst3D,-1
|
||||
mov poolRail3D,0
|
||||
mov poolBreakRails3D,0
|
||||
mov poolPotted3D,0
|
||||
mov poolFoul3D,0
|
||||
mov pyrFoulReason3D,0
|
||||
mov pyrValidEnd3D,0
|
||||
mov pyrSettled3D,0
|
||||
mov poolAccumulator3D,0
|
||||
mov poolTime3D,0
|
||||
mov poolState3D,POOL_STRIKE
|
||||
xor esi,esi
|
||||
pyr_shoot_history:
|
||||
mov pyrHistoryRails3D[esi*4],0
|
||||
mov pyrHistoryCross3D[esi*4],0
|
||||
mov pyrRailHalf3D[esi*4],0
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_shoot_history
|
||||
call PyramidDirection3D
|
||||
pyr_shoot_done:
|
||||
ret
|
||||
PoolShoot3D ENDP
|
||||
|
||||
; Obstruction checks use Q4 geometry with a 64-bit projection numerator.
|
||||
PyramidPathClear3D PROC uses ebx esi edi sx:DWORD,sy:DWORD,ex:DWORD,ey:DWORD,skipA:DWORD,skipB:DWORD
|
||||
local deltaX:DWORD,deltaY:DWORD,length2:DWORD,projection:DWORD,wx:DWORD,wy:DWORD
|
||||
mov eax,ex
|
||||
sub eax,sx
|
||||
sar eax,12
|
||||
mov deltaX,eax
|
||||
imul eax,eax
|
||||
mov ebx,eax
|
||||
mov eax,ey
|
||||
sub eax,sy
|
||||
sar eax,12
|
||||
mov deltaY,eax
|
||||
imul eax,eax
|
||||
add eax,ebx
|
||||
mov length2,eax
|
||||
test eax,eax
|
||||
jz pyr_path_bad
|
||||
xor esi,esi
|
||||
pyr_path_ball:
|
||||
cmp esi,skipA
|
||||
je pyr_path_next
|
||||
cmp esi,skipB
|
||||
je pyr_path_next
|
||||
cmp poolActive3D[esi*4],1
|
||||
jne pyr_path_next
|
||||
mov eax,poolX3D[esi*4]
|
||||
sub eax,sx
|
||||
sar eax,12
|
||||
mov wx,eax
|
||||
imul eax,deltaX
|
||||
mov ebx,eax
|
||||
mov eax,poolY3D[esi*4]
|
||||
sub eax,sy
|
||||
sar eax,12
|
||||
mov wy,eax
|
||||
imul eax,deltaY
|
||||
add eax,ebx
|
||||
test eax,eax
|
||||
jle pyr_path_next
|
||||
cmp eax,length2
|
||||
jge pyr_path_next
|
||||
mov ecx,FP_1
|
||||
imul ecx
|
||||
idiv length2
|
||||
mov projection,eax
|
||||
imul deltaX
|
||||
shrd eax,edx,16
|
||||
sub eax,wx
|
||||
imul eax,eax
|
||||
mov ebx,eax
|
||||
mov eax,projection
|
||||
imul deltaY
|
||||
shrd eax,edx,16
|
||||
sub eax,wy
|
||||
imul eax,eax
|
||||
add eax,ebx
|
||||
cmp eax,25*16*16
|
||||
jb pyr_path_bad
|
||||
pyr_path_next:
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_path_ball
|
||||
mov eax,1
|
||||
ret
|
||||
pyr_path_bad:
|
||||
xor eax,eax
|
||||
ret
|
||||
PyramidPathClear3D ENDP
|
||||
|
||||
; Search every cue/target/pocket triple; no hidden outcomes or teleported pots.
|
||||
PoolChooseAI3D PROC uses ebx esi edi
|
||||
local cue:DWORD,target:DWORD,pocket:DWORD,deltaX:DWORD,deltaY:DWORD,distance:DWORD
|
||||
local gx:DWORD,gy:DWORD,best:DWORD,bestCue:DWORD,bestX:DWORD,bestY:DWORD,bestPower:DWORD
|
||||
local shotLength:DWORD
|
||||
cmp poolBreak3D,0
|
||||
je pyr_ai_search
|
||||
mov pyrCue3D,0
|
||||
mov poolAngle3D,0
|
||||
mov pyrFineActive3D,0
|
||||
mov poolPower3D,85000
|
||||
ret
|
||||
pyr_ai_search:
|
||||
mov best,7FFFFFFFh
|
||||
mov bestCue,-1
|
||||
mov cue,0
|
||||
pyr_ai_cue:
|
||||
mov ecx,cue
|
||||
cmp poolActive3D[ecx*4],1
|
||||
jne pyr_ai_next_cue
|
||||
mov target,0
|
||||
pyr_ai_target:
|
||||
mov esi,target
|
||||
cmp esi,cue
|
||||
je pyr_ai_next_target
|
||||
cmp poolActive3D[esi*4],1
|
||||
jne pyr_ai_next_target
|
||||
mov pocket,0
|
||||
pyr_ai_pocket:
|
||||
mov edi,pocket
|
||||
mov eax,poolPocketX3D[edi*4]
|
||||
sub eax,poolX3D[esi*4]
|
||||
mov deltaX,eax
|
||||
mov eax,poolPocketY3D[edi*4]
|
||||
sub eax,poolY3D[esi*4]
|
||||
mov deltaY,eax
|
||||
invoke PyramidDistance3D,deltaX,deltaY
|
||||
test eax,eax
|
||||
jz pyr_ai_next_pocket
|
||||
mov distance,eax
|
||||
mov eax,deltaX
|
||||
mov ecx,POOL_DIAMETER
|
||||
imul ecx
|
||||
idiv distance
|
||||
mov ebx,poolX3D[esi*4]
|
||||
sub ebx,eax
|
||||
mov gx,ebx
|
||||
mov eax,deltaY
|
||||
mov ecx,POOL_DIAMETER
|
||||
imul ecx
|
||||
idiv distance
|
||||
mov ebx,poolY3D[esi*4]
|
||||
sub ebx,eax
|
||||
mov gy,ebx
|
||||
cmp gx,30*FP_1+POOL_RADIUS
|
||||
jl pyr_ai_next_pocket
|
||||
cmp gx,290*FP_1-POOL_RADIUS
|
||||
jg pyr_ai_next_pocket
|
||||
cmp gy,50*FP_1+POOL_RADIUS
|
||||
jl pyr_ai_next_pocket
|
||||
cmp gy,180*FP_1-POOL_RADIUS
|
||||
jg pyr_ai_next_pocket
|
||||
mov ecx,cue
|
||||
mov eax,gx
|
||||
sub eax,poolX3D[ecx*4]
|
||||
sar eax,12
|
||||
mov ebx,deltaX
|
||||
sar ebx,12
|
||||
imul eax,ebx
|
||||
mov ebx,eax
|
||||
mov eax,gy
|
||||
sub eax,poolY3D[ecx*4]
|
||||
sar eax,12
|
||||
mov edx,deltaY
|
||||
sar edx,12
|
||||
imul eax,edx
|
||||
add eax,ebx
|
||||
test eax,eax
|
||||
jle pyr_ai_next_pocket
|
||||
invoke PyramidPathClear3D,poolX3D[ecx*4],poolY3D[ecx*4],gx,gy,cue,target
|
||||
test eax,eax
|
||||
jz pyr_ai_next_pocket
|
||||
mov edi,pocket
|
||||
invoke PyramidPathClear3D,poolX3D[esi*4],poolY3D[esi*4],poolPocketX3D[edi*4],poolPocketY3D[edi*4],cue,target
|
||||
test eax,eax
|
||||
jz pyr_ai_next_pocket
|
||||
mov ecx,cue
|
||||
mov eax,gx
|
||||
sub eax,poolX3D[ecx*4]
|
||||
mov ebx,gy
|
||||
sub ebx,poolY3D[ecx*4]
|
||||
invoke PyramidDistance3D,eax,ebx
|
||||
mov shotLength,eax
|
||||
add eax,distance
|
||||
cmp eax,best
|
||||
jae pyr_ai_next_pocket
|
||||
mov best,eax
|
||||
mov ecx,cue
|
||||
mov bestCue,ecx
|
||||
mov ecx,gx
|
||||
mov bestX,ecx
|
||||
mov ecx,gy
|
||||
mov bestY,ecx
|
||||
; v^2/(2*rolling loss) estimates the travel budget, with margin for a cut.
|
||||
sar eax,16
|
||||
imul eax,220
|
||||
add eax,22000
|
||||
cmp eax,85000
|
||||
jbe @F
|
||||
mov eax,85000
|
||||
@@:
|
||||
mov bestPower,eax
|
||||
pyr_ai_next_pocket:
|
||||
inc pocket
|
||||
cmp pocket,6
|
||||
jb pyr_ai_pocket
|
||||
pyr_ai_next_target:
|
||||
inc target
|
||||
cmp target,16
|
||||
jb pyr_ai_target
|
||||
pyr_ai_next_cue:
|
||||
inc cue
|
||||
cmp cue,16
|
||||
jb pyr_ai_cue
|
||||
cmp bestCue,-1
|
||||
je pyr_ai_safety
|
||||
mov eax,bestCue
|
||||
mov pyrCue3D,eax
|
||||
invoke PoolAimPoint3D,bestX,bestY
|
||||
mov eax,bestPower
|
||||
mov poolPower3D,eax
|
||||
ret
|
||||
pyr_ai_safety:
|
||||
invoke PyramidSelect3D,-1
|
||||
mov esi,pyrCue3D
|
||||
xor edi,edi
|
||||
pyr_ai_safety_target:
|
||||
cmp edi,esi
|
||||
je @F
|
||||
cmp poolActive3D[edi*4],1
|
||||
je pyr_ai_safety_found
|
||||
@@:
|
||||
inc edi
|
||||
cmp edi,16
|
||||
jb pyr_ai_safety_target
|
||||
ret
|
||||
pyr_ai_safety_found:
|
||||
invoke PoolAimPoint3D,poolX3D[edi*4],poolY3D[edi*4]
|
||||
mov poolPower3D,65000
|
||||
ret
|
||||
PoolChooseAI3D ENDP
|
||||
|
||||
HandlePool3D PROC uses ebx esi edi
|
||||
xor esi,esi
|
||||
pyr_sink_tick:
|
||||
mov eax,deltaTime3D
|
||||
sub poolSinkTime3D[esi*4],eax
|
||||
jnc @F
|
||||
mov poolSinkTime3D[esi*4],0
|
||||
@@:
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_sink_tick
|
||||
mov eax,deltaTime3D
|
||||
add poolTime3D,eax
|
||||
cmp mouseClick3D,0
|
||||
je pyr_update
|
||||
cmp mouseY3D,3
|
||||
jb pyr_update
|
||||
cmp mouseY3D,17
|
||||
jae pyr_update
|
||||
cmp mouseX3D,252
|
||||
jb pyr_update
|
||||
cmp mouseX3D,312
|
||||
jae pyr_update
|
||||
mov engineMode,MODE_WALK
|
||||
call ClearKeys3D
|
||||
call SaveProgress3D
|
||||
ret
|
||||
pyr_update:
|
||||
cmp poolState3D,POOL_MOVING
|
||||
jne pyr_strike
|
||||
add poolAccumulator3D,eax
|
||||
pyr_fixed_tick:
|
||||
cmp poolAccumulator3D,2
|
||||
jb pyr_handle_done
|
||||
sub poolAccumulator3D,2
|
||||
call PoolStep3D
|
||||
cmp poolStill3D,0
|
||||
je pyr_fixed_tick
|
||||
call PoolFinishShot3D
|
||||
ret
|
||||
pyr_strike:
|
||||
cmp poolState3D,POOL_STRIKE
|
||||
jne pyr_idle
|
||||
cmp poolTime3D,240
|
||||
jb pyr_handle_done
|
||||
mov ebx,pyrCue3D
|
||||
mov eax,pyrDirX3D
|
||||
imul poolPower3D
|
||||
shrd eax,edx,16
|
||||
mov poolVX3D[ebx*4],eax
|
||||
mov eax,pyrDirY3D
|
||||
imul poolPower3D
|
||||
shrd eax,edx,16
|
||||
mov poolVY3D[ebx*4],eax
|
||||
mov poolState3D,POOL_MOVING
|
||||
mov poolAccumulator3D,0
|
||||
ret
|
||||
pyr_idle:
|
||||
cmp poolState3D,POOL_RESULT
|
||||
jne pyr_actor
|
||||
invoke Pressed3D,20h
|
||||
test eax,eax
|
||||
jnz pyr_restart
|
||||
cmp mouseClick3D,0
|
||||
je pyr_handle_done
|
||||
cmp mouseY3D,211
|
||||
jb pyr_handle_done
|
||||
cmp mouseX3D,202
|
||||
jb pyr_handle_done
|
||||
pyr_restart:
|
||||
call InitPool3D
|
||||
ret
|
||||
pyr_actor:
|
||||
cmp poolPlayer3D,1
|
||||
jne pyr_human
|
||||
cmp poolAI3D,0
|
||||
je pyr_human
|
||||
cmp poolTime3D,1000
|
||||
jb pyr_handle_done
|
||||
cmp poolState3D,POOL_PENALTY
|
||||
jne @F
|
||||
xor esi,esi
|
||||
pyr_ai_penalty:
|
||||
cmp poolActive3D[esi*4],1
|
||||
je pyr_ai_penalty_pick
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_ai_penalty
|
||||
ret
|
||||
pyr_ai_penalty_pick:
|
||||
invoke PyramidPenalty3D,esi
|
||||
ret
|
||||
@@:
|
||||
cmp poolState3D,POOL_CHOICE
|
||||
jne @F
|
||||
invoke PyramidChoice3D,0
|
||||
ret
|
||||
@@:
|
||||
call PoolChooseAI3D
|
||||
call PoolShoot3D
|
||||
ret
|
||||
pyr_human:
|
||||
cmp poolState3D,POOL_CHOICE
|
||||
jne pyr_human_penalty
|
||||
mov esi,0
|
||||
pyr_choice_key:
|
||||
lea eax,[esi+31h]
|
||||
invoke Pressed3D,eax
|
||||
test eax,eax
|
||||
jnz pyr_choice_selected
|
||||
inc esi
|
||||
cmp esi,4
|
||||
jb pyr_choice_key
|
||||
invoke Pressed3D,0Dh
|
||||
test eax,eax
|
||||
jz @F
|
||||
xor esi,esi
|
||||
jmp pyr_choice_selected
|
||||
@@:
|
||||
cmp mouseClick3D,0
|
||||
je pyr_handle_done
|
||||
cmp mouseY3D,215
|
||||
jb pyr_handle_done
|
||||
cmp mouseY3D,237
|
||||
jae pyr_handle_done
|
||||
mov eax,mouseX3D
|
||||
sub eax,8
|
||||
js pyr_handle_done
|
||||
xor edx,edx
|
||||
mov ecx,78
|
||||
div ecx
|
||||
cmp edx,70
|
||||
jae pyr_handle_done
|
||||
mov esi,eax
|
||||
pyr_choice_selected:
|
||||
invoke PyramidChoice3D,esi
|
||||
ret
|
||||
pyr_human_penalty:
|
||||
cmp poolState3D,POOL_PENALTY
|
||||
jne pyr_human_aim
|
||||
invoke Pressed3D,0Dh
|
||||
test eax,eax
|
||||
jnz pyr_penalty_skip
|
||||
cmp mouseClick3D,0
|
||||
je pyr_handle_done
|
||||
cmp mouseY3D,215
|
||||
jb @F
|
||||
cmp mouseY3D,238
|
||||
jae @F
|
||||
cmp mouseX3D,202
|
||||
jae pyr_penalty_skip
|
||||
@@:
|
||||
mov eax,mouseX3D
|
||||
shl eax,16
|
||||
mov ebx,mouseY3D
|
||||
shl ebx,16
|
||||
invoke PyramidPick3D,eax,ebx
|
||||
cmp eax,-1
|
||||
je pyr_handle_done
|
||||
invoke PyramidPenalty3D,eax
|
||||
ret
|
||||
pyr_penalty_skip:
|
||||
mov poolState3D,POOL_CHOICE
|
||||
ret
|
||||
pyr_human_aim:
|
||||
cmp mouseClick3D,0
|
||||
je pyr_keys
|
||||
mov mouseClick3D,0
|
||||
mov eax,mouseX3D
|
||||
mov ebx,mouseY3D
|
||||
cmp ebx,50
|
||||
jb pyr_keys
|
||||
cmp ebx,180
|
||||
ja pyr_mouse_footer
|
||||
shl eax,16
|
||||
shl ebx,16
|
||||
cmp pyrPickClick3D,0
|
||||
je @F
|
||||
mov pyrPickClick3D,0
|
||||
invoke PyramidPick3D,eax,ebx
|
||||
cmp eax,-1
|
||||
je pyr_handle_done
|
||||
invoke PyramidSelect3D,eax
|
||||
ret
|
||||
@@:
|
||||
cmp poolBreak3D,0
|
||||
je pyr_mouse_aim
|
||||
cmp keys3D[10h],0
|
||||
je pyr_mouse_aim
|
||||
cmp eax,95*FP_1
|
||||
jge pyr_handle_done
|
||||
invoke PoolPlaceCue3D,eax,ebx
|
||||
ret
|
||||
pyr_mouse_aim:
|
||||
invoke PoolAimPoint3D,eax,ebx
|
||||
ret
|
||||
pyr_mouse_footer:
|
||||
cmp ebx,193
|
||||
jb pyr_keys
|
||||
cmp ebx,209
|
||||
ja pyr_mouse_command
|
||||
cmp eax,202
|
||||
jb pyr_keys
|
||||
cmp eax,308
|
||||
ja pyr_keys
|
||||
sub eax,202
|
||||
imul eax,82000
|
||||
xor edx,edx
|
||||
mov ecx,106
|
||||
div ecx
|
||||
add eax,8000
|
||||
mov poolPower3D,eax
|
||||
ret
|
||||
pyr_mouse_command:
|
||||
cmp ebx,211
|
||||
jb pyr_keys
|
||||
cmp ebx,238
|
||||
jae pyr_keys
|
||||
cmp eax,86
|
||||
jb pyr_cycle_cue
|
||||
cmp eax,196
|
||||
jb pyr_toggle_guide
|
||||
call PoolShoot3D
|
||||
ret
|
||||
pyr_keys:
|
||||
mov eax,deltaTime3D
|
||||
imul eax,120
|
||||
cmp keys3D[10h],0
|
||||
je @F
|
||||
mov eax,deltaTime3D
|
||||
imul eax,30
|
||||
@@:
|
||||
add eax,pyrAimCarry3D
|
||||
xor edx,edx
|
||||
mov ecx,1000
|
||||
div ecx
|
||||
mov pyrAimCarry3D,edx
|
||||
mov ebx,eax
|
||||
cmp pyrFineActive3D,0
|
||||
jne @F
|
||||
mov eax,poolAngle3D
|
||||
shl eax,3
|
||||
mov pyrFine3D,eax
|
||||
@@:
|
||||
cmp keys3D[25h],0
|
||||
je @F
|
||||
sub pyrFine3D,ebx
|
||||
mov pyrFineActive3D,1
|
||||
@@:
|
||||
cmp keys3D[27h],0
|
||||
je @F
|
||||
add pyrFine3D,ebx
|
||||
mov pyrFineActive3D,1
|
||||
@@:
|
||||
and pyrFine3D,4095
|
||||
mov eax,deltaTime3D
|
||||
imul eax,100
|
||||
cmp keys3D[26h],0
|
||||
je @F
|
||||
add poolPower3D,eax
|
||||
@@:
|
||||
cmp keys3D[28h],0
|
||||
je @F
|
||||
sub poolPower3D,eax
|
||||
@@:
|
||||
cmp poolPower3D,8000
|
||||
jge @F
|
||||
mov poolPower3D,8000
|
||||
@@:
|
||||
cmp poolPower3D,90000
|
||||
jle @F
|
||||
mov poolPower3D,90000
|
||||
@@:
|
||||
invoke Pressed3D,42h
|
||||
test eax,eax
|
||||
jnz pyr_cycle_cue
|
||||
invoke Pressed3D,50h
|
||||
test eax,eax
|
||||
jnz pyr_toggle_guide
|
||||
invoke Pressed3D,20h
|
||||
test eax,eax
|
||||
jz pyr_handle_done
|
||||
call PoolShoot3D
|
||||
ret
|
||||
pyr_toggle_guide:
|
||||
xor pyrGuideOn3D,1
|
||||
ret
|
||||
pyr_cycle_cue:
|
||||
cmp poolBreak3D,0
|
||||
jne pyr_handle_done
|
||||
mov esi,pyrCue3D
|
||||
mov edi,16
|
||||
pyr_cycle_scan:
|
||||
inc esi
|
||||
and esi,15
|
||||
cmp poolActive3D[esi*4],1
|
||||
je pyr_cycle_found
|
||||
dec edi
|
||||
jnz pyr_cycle_scan
|
||||
ret
|
||||
pyr_cycle_found:
|
||||
invoke PyramidSelect3D,esi
|
||||
pyr_handle_done:
|
||||
ret
|
||||
HandlePool3D ENDP
|
||||
378
src_graphics/pyramid_render.inc
Normal file
|
|
@ -0,0 +1,378 @@
|
|||
PyramidBall3D PROC uses ebx esi ball:DWORD,x:DWORD,y:DWORD,sizePx:DWORD
|
||||
mov ebx,ball
|
||||
mov eax,pyrRoll3D[ebx*4]
|
||||
shr eax,17
|
||||
and eax,3
|
||||
test ebx,ebx
|
||||
jnz @F
|
||||
add eax,4
|
||||
@@:
|
||||
mov esi,eax
|
||||
mov eax,sizePx
|
||||
shr eax,1
|
||||
mov edx,x
|
||||
sub edx,eax
|
||||
mov ecx,y
|
||||
sub ecx,eax
|
||||
invoke DrawAnimSprite3D,OFFSET pyrBallsPack3D,esi,edx,ecx,sizePx,sizePx
|
||||
cmp sizePx,12
|
||||
jne pyr_ball_done
|
||||
test ebx,ebx
|
||||
jz pyr_ball_done
|
||||
mov esi,x
|
||||
sub esi,1
|
||||
mov eax,y
|
||||
sub eax,2
|
||||
cmp ebx,10
|
||||
jb @F
|
||||
sub esi,2
|
||||
invoke DrawWheelDigit3D,esi,eax,1,1,003B3933h
|
||||
add esi,4
|
||||
mov eax,y
|
||||
sub eax,2
|
||||
sub ebx,10
|
||||
@@:
|
||||
invoke DrawWheelDigit3D,esi,eax,ebx,1,003B3933h
|
||||
pyr_ball_done:
|
||||
ret
|
||||
PyramidBall3D ENDP
|
||||
|
||||
; A swept aim preview terminates on the first real ball or cushion.
|
||||
PyramidGuide3D PROC uses ebx esi edi
|
||||
local px:DWORD,py:DWORD,pointX:DWORD,pointY:DWORD
|
||||
mov pyrTarget3D,-1
|
||||
mov ebx,pyrCue3D
|
||||
mov eax,poolX3D[ebx*4]
|
||||
mov px,eax
|
||||
mov eax,poolY3D[ebx*4]
|
||||
mov py,eax
|
||||
mov esi,6
|
||||
pyr_guide_step:
|
||||
mov eax,pyrDirX3D
|
||||
imul esi
|
||||
sar eax,1
|
||||
add eax,px
|
||||
mov pointX,eax
|
||||
mov eax,pyrDirY3D
|
||||
imul esi
|
||||
sar eax,1
|
||||
add eax,py
|
||||
mov pointY,eax
|
||||
cmp pointX,30*FP_1+POOL_RADIUS
|
||||
jl pyr_guide_done
|
||||
cmp pointX,290*FP_1-POOL_RADIUS
|
||||
jg pyr_guide_done
|
||||
cmp pointY,50*FP_1+POOL_RADIUS
|
||||
jl pyr_guide_done
|
||||
cmp pointY,180*FP_1-POOL_RADIUS
|
||||
jg pyr_guide_done
|
||||
xor edi,edi
|
||||
pyr_guide_obstacle:
|
||||
cmp edi,pyrCue3D
|
||||
je pyr_guide_next_obstacle
|
||||
cmp poolActive3D[edi*4],1
|
||||
jne pyr_guide_next_obstacle
|
||||
mov eax,pointX
|
||||
sub eax,poolX3D[edi*4]
|
||||
sar eax,12
|
||||
imul eax,eax
|
||||
mov ebx,eax
|
||||
mov eax,pointY
|
||||
sub eax,poolY3D[edi*4]
|
||||
sar eax,12
|
||||
imul eax,eax
|
||||
add eax,ebx
|
||||
cmp eax,25*16*16
|
||||
jb pyr_guide_hit
|
||||
pyr_guide_next_obstacle:
|
||||
inc edi
|
||||
cmp edi,16
|
||||
jb pyr_guide_obstacle
|
||||
test esi,7
|
||||
jnz pyr_guide_next
|
||||
mov eax,pointX
|
||||
sar eax,16
|
||||
mov ebx,pointY
|
||||
sar ebx,16
|
||||
invoke DrawPixel,eax,ebx,00B1D7CFh
|
||||
pyr_guide_next:
|
||||
inc esi
|
||||
cmp esi,560
|
||||
jb pyr_guide_step
|
||||
pyr_guide_done:
|
||||
ret
|
||||
pyr_guide_hit:
|
||||
mov pyrTarget3D,edi
|
||||
mov eax,pointX
|
||||
mov pyrGuideX3D,eax
|
||||
sar eax,16
|
||||
mov ebx,pointY
|
||||
mov pyrGuideY3D,ebx
|
||||
sar ebx,16
|
||||
invoke DrawCircle,eax,ebx,3,00B1D7CFh
|
||||
mov eax,pointX
|
||||
sar eax,16
|
||||
mov ebx,pointY
|
||||
sar ebx,16
|
||||
invoke DrawCircle,eax,ebx,2,00295041h
|
||||
ret
|
||||
PyramidGuide3D ENDP
|
||||
|
||||
RenderPool3D PROC uses ebx esi edi
|
||||
local px:DWORD,py:DWORD,tip:DWORD,dirx:DWORD,diry:DWORD
|
||||
mov esi,pyrTablePack3D.pixels
|
||||
test esi,esi
|
||||
jz pyr_render_missing
|
||||
lea edi,screenBuffer
|
||||
mov ecx,SCREEN_SIZE
|
||||
rep movsd
|
||||
xor esi,esi
|
||||
pyr_render_mouths:
|
||||
mov eax,poolPocketX3D[esi*4]
|
||||
sar eax,16
|
||||
mov ebx,poolPocketY3D[esi*4]
|
||||
sar ebx,16
|
||||
invoke DrawCircle,eax,ebx,3,000B1010h
|
||||
inc esi
|
||||
cmp esi,6
|
||||
jb pyr_render_mouths
|
||||
invoke DrawPixel,95,115,00838C73h
|
||||
invoke DrawPixel,160,115,00838C73h
|
||||
invoke DrawPixel,225,115,00838C73h
|
||||
cmp poolBreak3D,0
|
||||
je @F
|
||||
invoke DrawBox,95,53,1,124,003C7261h
|
||||
@@:
|
||||
cmp poolState3D,POOL_AIM
|
||||
jne pyr_render_objects
|
||||
call PyramidDirection3D
|
||||
cmp pyrGuideOn3D,0
|
||||
je pyr_render_objects
|
||||
call PyramidGuide3D
|
||||
pyr_render_objects:
|
||||
xor esi,esi
|
||||
pyr_render_ball:
|
||||
cmp poolActive3D[esi*4],1
|
||||
jne pyr_render_sunk
|
||||
mov eax,poolX3D[esi*4]
|
||||
sar eax,15
|
||||
mov px,eax
|
||||
mov eax,poolY3D[esi*4]
|
||||
sar eax,15
|
||||
mov py,eax
|
||||
cmp esi,pyrCue3D
|
||||
jne @F
|
||||
cmp poolState3D,POOL_AIM
|
||||
jne @F
|
||||
mov eax,px
|
||||
sar eax,1
|
||||
mov ebx,py
|
||||
sar ebx,1
|
||||
invoke DrawCircle,eax,ebx,4,007BAFACh
|
||||
@@:
|
||||
invoke PyramidBall3D,esi,px,py,12
|
||||
jmp pyr_render_next
|
||||
pyr_render_sunk:
|
||||
cmp poolSinkTime3D[esi*4],0
|
||||
je pyr_render_next
|
||||
mov ecx,poolPocket3D[esi*4]
|
||||
cmp ecx,5
|
||||
ja pyr_render_next
|
||||
mov eax,poolPocketX3D[ecx*4]
|
||||
sar eax,15
|
||||
mov px,eax
|
||||
mov eax,poolPocketY3D[ecx*4]
|
||||
sar eax,15
|
||||
mov py,eax
|
||||
mov eax,poolSinkTime3D[esi*4]
|
||||
imul eax,12
|
||||
xor edx,edx
|
||||
mov ecx,220
|
||||
div ecx
|
||||
test eax,eax
|
||||
jz pyr_render_next
|
||||
invoke PyramidBall3D,esi,px,py,eax
|
||||
pyr_render_next:
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_render_ball
|
||||
cmp poolState3D,POOL_AIM
|
||||
je pyr_render_cue
|
||||
cmp poolState3D,POOL_STRIKE
|
||||
jne pyr_render_hud
|
||||
pyr_render_cue:
|
||||
mov ebx,pyrCue3D
|
||||
mov eax,poolX3D[ebx*4]
|
||||
mov px,eax
|
||||
mov eax,poolY3D[ebx*4]
|
||||
mov py,eax
|
||||
mov eax,pyrDirX3D
|
||||
mov dirx,eax
|
||||
mov eax,pyrDirY3D
|
||||
mov diry,eax
|
||||
mov tip,5
|
||||
cmp poolState3D,POOL_STRIKE
|
||||
jne @F
|
||||
mov tip,3
|
||||
mov eax,240
|
||||
sub eax,poolTime3D
|
||||
cmp eax,0
|
||||
jge pyr_cue_time
|
||||
xor eax,eax
|
||||
pyr_cue_time:
|
||||
shr eax,4
|
||||
add tip,eax
|
||||
@@:
|
||||
mov esi,tip
|
||||
mov edi,44
|
||||
pyr_cue_draw:
|
||||
mov eax,dirx
|
||||
imul esi
|
||||
neg eax
|
||||
add eax,px
|
||||
sar eax,16
|
||||
mov ebx,eax
|
||||
mov eax,diry
|
||||
imul esi
|
||||
neg eax
|
||||
add eax,py
|
||||
sar eax,16
|
||||
mov tip,eax
|
||||
invoke DrawCircle,ebx,eax,1,003E2E23h
|
||||
invoke DrawPixel,ebx,tip,00DCC59Ah
|
||||
inc esi
|
||||
dec edi
|
||||
jnz pyr_cue_draw
|
||||
pyr_render_hud:
|
||||
invoke DrawBox,0,0,320,20,00151D20h
|
||||
invoke DrawString8x8,8,6,OFFSET pyrTitle3D,00E8D7ADh
|
||||
invoke DrawNumber,112,6,pyrScore3D,00F4F3E8h
|
||||
invoke DrawString8x8,128,6,OFFSET pyrScoreSep3D,00E8D7ADh
|
||||
invoke DrawNumber,144,6,pyrScore3D[4],00F4F3E8h
|
||||
mov ebx,OFFSET pyrPlayerName3D
|
||||
cmp poolPlayer3D,0
|
||||
je @F
|
||||
mov ebx,OFFSET pyrAIName3D
|
||||
@@:
|
||||
invoke DrawString8x8,184,6,ebx,00A8DDB9h
|
||||
invoke DrawBoxBorder,252,3,60,14,002C3637h,00687672h,1
|
||||
invoke DrawString8x8,258,6,OFFSET cardExitButton3D,00E9D8B0h
|
||||
mov ebx,OFFSET pyrTurnText3D
|
||||
cmp poolBreak3D,0
|
||||
je @F
|
||||
mov ebx,OFFSET pyrBreakText3D
|
||||
@@:
|
||||
cmp poolState3D,POOL_PENALTY
|
||||
jne @F
|
||||
mov ebx,OFFSET pyrPenaltyText3D
|
||||
@@:
|
||||
cmp poolState3D,POOL_CHOICE
|
||||
jne @F
|
||||
mov ebx,OFFSET pyrChoiceText3D
|
||||
@@:
|
||||
cmp poolState3D,POOL_MOVING
|
||||
jne @F
|
||||
mov ebx,OFFSET poolMovingText3D
|
||||
@@:
|
||||
cmp poolState3D,POOL_STRIKE
|
||||
jne @F
|
||||
mov ebx,OFFSET poolShotText3D
|
||||
@@:
|
||||
invoke DrawBox,0,22,320,15,00151D20h
|
||||
invoke DrawString8x8,8,26,ebx,00E8D7ADh
|
||||
cmp poolState3D,POOL_PENALTY
|
||||
je @F
|
||||
cmp poolState3D,POOL_CHOICE
|
||||
jne pyr_render_footer
|
||||
@@:
|
||||
mov ecx,pyrFoulReason3D
|
||||
mov eax,pyrStatusNames3D[ecx*4]
|
||||
invoke DrawString8x8,176,26,eax,00EAAD9Ah
|
||||
pyr_render_footer:
|
||||
invoke DrawBox,0,186,320,54,00151D20h
|
||||
xor esi,esi
|
||||
mov ebx,20
|
||||
mov edi,174
|
||||
pyr_render_shelves:
|
||||
mov eax,pyrOwner3D[esi*4]
|
||||
test eax,eax
|
||||
js pyr_shelf_next
|
||||
cmp eax,1
|
||||
jne pyr_shelf_player
|
||||
invoke PyramidBall3D,esi,edi,381,10
|
||||
add edi,12
|
||||
jmp pyr_shelf_next
|
||||
pyr_shelf_player:
|
||||
invoke PyramidBall3D,esi,ebx,381,10
|
||||
add ebx,12
|
||||
pyr_shelf_next:
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_render_shelves
|
||||
invoke DrawString8x8,202,187,OFFSET poolPowerText3D,00CCBE94h
|
||||
mov eax,poolPower3D
|
||||
sub eax,8000
|
||||
imul eax,100
|
||||
xor edx,edx
|
||||
mov ecx,82000
|
||||
div ecx
|
||||
invoke DrawNumber,254,187,eax,00FFFFFFh
|
||||
mov eax,poolPower3D
|
||||
sub eax,8000
|
||||
imul eax,106
|
||||
xor edx,edx
|
||||
mov ecx,82000
|
||||
div ecx
|
||||
mov tip,eax
|
||||
invoke DrawBox,202,201,106,5,00363D36h
|
||||
invoke DrawBox,202,201,tip,5,00D5BB73h
|
||||
mov eax,tip
|
||||
add eax,201
|
||||
invoke DrawBox,eax,199,2,9,00F4F0DDh
|
||||
invoke DrawBoxBorder,12,215,74,22,0039412Fh,00AC9862h,1
|
||||
invoke DrawString8x8,18,222,OFFSET pyrCueText3D,00FFFFFFh
|
||||
invoke DrawNumber,62,222,pyrCue3D,00EAD19Bh
|
||||
invoke DrawBoxBorder,92,215,104,22,0039412Fh,00AC9862h,1
|
||||
invoke DrawString8x8,106,222,OFFSET pyrGuideText3D,00FFFFFFh
|
||||
invoke DrawBoxBorder,202,215,106,22,00425232h,00BBA76Fh,1
|
||||
mov ebx,OFFSET poolShotText3D
|
||||
cmp poolState3D,POOL_PENALTY
|
||||
jne @F
|
||||
mov ebx,OFFSET pyrSkipText3D
|
||||
@@:
|
||||
cmp poolState3D,POOL_RESULT
|
||||
jne @F
|
||||
mov ebx,OFFSET poolRackText3D
|
||||
@@:
|
||||
invoke DrawString8x8,226,222,ebx,00FFFFFFh
|
||||
cmp poolState3D,POOL_CHOICE
|
||||
jne pyr_render_result
|
||||
invoke DrawBox,0,211,320,29,00151D20h
|
||||
invoke DrawBoxBorder,8,215,70,22,0039412Fh,00AC9862h,1
|
||||
invoke DrawString8x8,19,222,OFFSET pyrPlayText3D,00FFFFFFh
|
||||
invoke DrawBoxBorder,86,215,70,22,0039412Fh,00AC9862h,1
|
||||
invoke DrawString8x8,89,222,OFFSET pyrPassText3D,00FFFFFFh
|
||||
cmp pyrIllegalBreak3D,0
|
||||
je pyr_render_result
|
||||
invoke DrawBoxBorder,164,215,70,22,0039412Fh,00AC9862h,1
|
||||
invoke DrawString8x8,167,222,OFFSET pyrRackText3D,00FFFFFFh
|
||||
invoke DrawBoxBorder,242,215,70,22,0039412Fh,00AC9862h,1
|
||||
invoke DrawString8x8,249,222,OFFSET pyrTheirBreakText3D,00FFFFFFh
|
||||
pyr_render_result:
|
||||
cmp poolState3D,POOL_RESULT
|
||||
jne pyr_render_done
|
||||
invoke DrawBoxBorder,76,88,168,43,00192720h,00D6B971h,2
|
||||
mov ebx,OFFSET pyrPlayerName3D
|
||||
cmp poolWinner3D,0
|
||||
je @F
|
||||
mov ebx,OFFSET pyrAIName3D
|
||||
@@:
|
||||
invoke DrawString8x8,92,100,ebx,00FFFFFFh
|
||||
invoke DrawString8x8,92,115,OFFSET poolWinText3D,00E8D7ADh
|
||||
pyr_render_done:
|
||||
ret
|
||||
pyr_render_missing:
|
||||
invoke DrawBox,0,0,320,240,00151D20h
|
||||
invoke DrawString8x8,56,108,OFFSET unavailableText3D,00E8D7ADh
|
||||
ret
|
||||
RenderPool3D ENDP
|
||||
571
src_graphics/pyramid_rules.inc
Normal file
|
|
@ -0,0 +1,571 @@
|
|||
InitPyramidState3D PROC uses esi edi
|
||||
mov pyrCue3D,0
|
||||
mov poolFirst3D,-1
|
||||
mov pyrScore3D,0
|
||||
mov pyrScore3D[4],0
|
||||
mov pyrFine3D,0
|
||||
mov pyrFineActive3D,0
|
||||
mov pyrAimCarry3D,0
|
||||
mov pyrPickClick3D,0
|
||||
mov pyrSettled3D,0
|
||||
mov pyrFoulReason3D,0
|
||||
mov pyrIllegalBreak3D,0
|
||||
mov pyrValidEnd3D,0
|
||||
xor esi,esi
|
||||
pyr_init_records:
|
||||
mov pyrOwner3D[esi*4],-1
|
||||
mov pyrRoll3D[esi*4],0
|
||||
mov pyrHistoryRails3D[esi*4],0
|
||||
mov pyrHistoryCross3D[esi*4],0
|
||||
mov pyrRailHalf3D[esi*4],0
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_init_records
|
||||
invoke LoadAnimPack3D,OFFSET pyrTablePack3D,OFFSET pyrTablePath3D
|
||||
invoke LoadAnimPack3D,OFFSET pyrBallsPack3D,OFFSET pyrBallsPath3D
|
||||
ret
|
||||
InitPyramidState3D ENDP
|
||||
|
||||
FreePyramidAssets3D PROC
|
||||
invoke FreeAnimPack3D,OFFSET pyrTablePack3D
|
||||
invoke FreeAnimPack3D,OFFSET pyrBallsPack3D
|
||||
ret
|
||||
FreePyramidAssets3D ENDP
|
||||
|
||||
; Q4 length calculation avoids the signed overflow of long Q8 table vectors.
|
||||
PyramidDistance3D PROC uses ebx deltaX:DWORD,deltaY:DWORD
|
||||
mov eax,deltaX
|
||||
sar eax,12
|
||||
imul eax,eax
|
||||
mov ebx,eax
|
||||
mov eax,deltaY
|
||||
sar eax,12
|
||||
imul eax,eax
|
||||
add eax,ebx
|
||||
invoke PoolSqrt3D,eax
|
||||
shl eax,12
|
||||
ret
|
||||
PyramidDistance3D ENDP
|
||||
|
||||
PyramidContact3D PROC uses ebx esi edi a:DWORD,b:DWORD
|
||||
mov esi,a
|
||||
mov edi,b
|
||||
cmp poolFirst3D,-1
|
||||
jne pyr_contact_events
|
||||
cmp esi,pyrCue3D
|
||||
jne @F
|
||||
mov poolFirst3D,edi
|
||||
jmp pyr_contact_events
|
||||
@@:
|
||||
cmp edi,pyrCue3D
|
||||
jne pyr_contact_done
|
||||
mov poolFirst3D,esi
|
||||
pyr_contact_events:
|
||||
; Ordered cushion/crossing history follows impulse transfers, not all balls.
|
||||
invoke PyramidContactEnd3D,esi,edi
|
||||
invoke PyramidContactEnd3D,edi,esi
|
||||
mov eax,pyrHistoryRails3D[esi*4]
|
||||
or eax,pyrHistoryRails3D[edi*4]
|
||||
mov pyrHistoryRails3D[esi*4],eax
|
||||
mov pyrHistoryRails3D[edi*4],eax
|
||||
mov eax,pyrHistoryCross3D[esi*4]
|
||||
or eax,pyrHistoryCross3D[edi*4]
|
||||
mov pyrHistoryCross3D[esi*4],eax
|
||||
mov pyrHistoryCross3D[edi*4],eax
|
||||
mov eax,pyrRailHalf3D[esi*4]
|
||||
or eax,pyrRailHalf3D[edi*4]
|
||||
mov pyrRailHalf3D[esi*4],eax
|
||||
mov pyrRailHalf3D[edi*4],eax
|
||||
pyr_contact_done:
|
||||
ret
|
||||
PyramidContact3D ENDP
|
||||
|
||||
PyramidContactEnd3D PROC uses ebx esi edi moving:DWORD,other:DWORD
|
||||
mov esi,moving
|
||||
mov edi,other
|
||||
test pyrRailHalf3D[esi*4],1
|
||||
jz @F
|
||||
cmp poolX3D[edi*4],160*FP_1
|
||||
jge pyr_contact_valid
|
||||
@@:
|
||||
test pyrRailHalf3D[esi*4],2
|
||||
jz @F
|
||||
cmp poolX3D[edi*4],160*FP_1
|
||||
jle pyr_contact_valid
|
||||
@@:
|
||||
; A frozen-ball contact counts only against an eligible cushion history.
|
||||
mov ebx,0
|
||||
cmp poolY3D[edi*4],50*FP_1+POOL_RADIUS+256
|
||||
jle pyr_contact_frozen
|
||||
mov ebx,1
|
||||
cmp poolY3D[edi*4],180*FP_1-POOL_RADIUS-256
|
||||
jge pyr_contact_frozen
|
||||
mov ebx,2
|
||||
cmp poolX3D[edi*4],30*FP_1+POOL_RADIUS+256
|
||||
jle pyr_contact_frozen
|
||||
mov ebx,3
|
||||
cmp poolX3D[edi*4],290*FP_1-POOL_RADIUS-256
|
||||
jl pyr_contact_end_done
|
||||
pyr_contact_frozen:
|
||||
cmp pyrHistoryCross3D[esi*4],0
|
||||
jne pyr_contact_valid
|
||||
mov eax,pyrHistoryRails3D[esi*4]
|
||||
mov ecx,ebx
|
||||
btr eax,ecx
|
||||
test eax,eax
|
||||
jz pyr_contact_end_done
|
||||
pyr_contact_valid:
|
||||
mov pyrValidEnd3D,1
|
||||
pyr_contact_end_done:
|
||||
ret
|
||||
PyramidContactEnd3D ENDP
|
||||
|
||||
PyramidRail3D PROC uses ebx ball:DWORD,side:DWORD
|
||||
cmp poolFirst3D,-1
|
||||
je pyr_rail_done
|
||||
mov ebx,ball
|
||||
mov eax,pyrHistoryRails3D[ebx*4]
|
||||
mov ecx,side
|
||||
btr eax,ecx
|
||||
test eax,eax
|
||||
jnz pyr_rail_valid
|
||||
cmp pyrHistoryCross3D[ebx*4],0
|
||||
je @F
|
||||
pyr_rail_valid:
|
||||
mov pyrValidEnd3D,1
|
||||
@@:
|
||||
mov ecx,side
|
||||
bts pyrHistoryRails3D[ebx*4],ecx
|
||||
mov eax,1
|
||||
cmp poolX3D[ebx*4],160*FP_1
|
||||
jl @F
|
||||
mov eax,2
|
||||
@@:
|
||||
or pyrRailHalf3D[ebx*4],eax
|
||||
pyr_rail_done:
|
||||
ret
|
||||
PyramidRail3D ENDP
|
||||
|
||||
PyramidCross3D PROC uses ebx ball:DWORD
|
||||
cmp poolFirst3D,-1
|
||||
je pyr_cross_done
|
||||
mov ebx,ball
|
||||
mov eax,pyrPreviousX3D[ebx*4]
|
||||
cmp eax,160*FP_1
|
||||
je pyr_cross_done
|
||||
jl pyr_cross_from_left
|
||||
cmp poolX3D[ebx*4],160*FP_1
|
||||
jge pyr_cross_done
|
||||
jmp pyr_cross_record
|
||||
pyr_cross_from_left:
|
||||
cmp poolX3D[ebx*4],160*FP_1
|
||||
jle pyr_cross_done
|
||||
pyr_cross_record:
|
||||
mov pyrHistoryCross3D[ebx*4],1
|
||||
cmp pyrHistoryRails3D[ebx*4],0
|
||||
je pyr_cross_done
|
||||
mov pyrValidEnd3D,1
|
||||
pyr_cross_done:
|
||||
ret
|
||||
PyramidCross3D ENDP
|
||||
|
||||
PyramidCanPlace3D PROC uses ebx esi ball:DWORD,px:DWORD,py:DWORD
|
||||
cmp px,30*FP_1+POOL_RADIUS
|
||||
jl pyr_place_bad
|
||||
cmp px,290*FP_1-POOL_RADIUS
|
||||
jg pyr_place_bad
|
||||
cmp py,50*FP_1+POOL_RADIUS
|
||||
jl pyr_place_bad
|
||||
cmp py,180*FP_1-POOL_RADIUS
|
||||
jg pyr_place_bad
|
||||
xor esi,esi
|
||||
pyr_place_scan:
|
||||
cmp esi,ball
|
||||
je pyr_place_next
|
||||
cmp poolActive3D[esi*4],0
|
||||
je pyr_place_next
|
||||
mov eax,px
|
||||
sub eax,poolX3D[esi*4]
|
||||
sar eax,12
|
||||
imul eax,eax
|
||||
mov ebx,eax
|
||||
mov eax,py
|
||||
sub eax,poolY3D[esi*4]
|
||||
sar eax,12
|
||||
imul eax,eax
|
||||
add eax,ebx
|
||||
cmp eax,25*16*16
|
||||
jbe pyr_place_bad
|
||||
pyr_place_next:
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_place_scan
|
||||
mov eax,1
|
||||
ret
|
||||
pyr_place_bad:
|
||||
xor eax,eax
|
||||
ret
|
||||
PyramidCanPlace3D ENDP
|
||||
|
||||
PyramidRespot3D PROC uses ebx esi ball:DWORD
|
||||
mov ebx,225*FP_1
|
||||
pyr_respot_foot:
|
||||
invoke PyramidCanPlace3D,ball,ebx,115*FP_1
|
||||
test eax,eax
|
||||
jnz pyr_respot_found
|
||||
add ebx,FP_1*501/100
|
||||
cmp ebx,287*FP_1
|
||||
jle pyr_respot_foot
|
||||
mov ebx,225*FP_1-FP_1*501/100
|
||||
pyr_respot_front:
|
||||
invoke PyramidCanPlace3D,ball,ebx,115*FP_1
|
||||
test eax,eax
|
||||
jnz pyr_respot_found
|
||||
sub ebx,FP_1*501/100
|
||||
cmp ebx,33*FP_1
|
||||
jge pyr_respot_front
|
||||
; Pathological layouts still keep every ball: bounded free-cloth fallback.
|
||||
mov esi,55*FP_1
|
||||
pyr_respot_row:
|
||||
mov ebx,35*FP_1
|
||||
pyr_respot_grid:
|
||||
invoke PyramidCanPlace3D,ball,ebx,esi
|
||||
test eax,eax
|
||||
jnz pyr_respot_grid_found
|
||||
add ebx,6*FP_1
|
||||
cmp ebx,285*FP_1
|
||||
jle pyr_respot_grid
|
||||
add esi,6*FP_1
|
||||
cmp esi,175*FP_1
|
||||
jle pyr_respot_row
|
||||
xor eax,eax
|
||||
ret
|
||||
pyr_respot_found:
|
||||
mov esi,115*FP_1
|
||||
pyr_respot_grid_found:
|
||||
mov ecx,ball
|
||||
mov poolX3D[ecx*4],ebx
|
||||
mov poolY3D[ecx*4],esi
|
||||
mov poolVX3D[ecx*4],0
|
||||
mov poolVY3D[ecx*4],0
|
||||
mov poolActive3D[ecx*4],1
|
||||
mov poolPocket3D[ecx*4],-1
|
||||
mov poolSinkTime3D[ecx*4],0
|
||||
mov pyrOwner3D[ecx*4],-1
|
||||
mov eax,1
|
||||
ret
|
||||
PyramidRespot3D ENDP
|
||||
|
||||
PoolPlaceCue3D PROC px:DWORD,py:DWORD
|
||||
invoke PyramidCanPlace3D,0,px,py
|
||||
test eax,eax
|
||||
jz @F
|
||||
mov eax,px
|
||||
mov poolX3D,eax
|
||||
mov eax,py
|
||||
mov poolY3D,eax
|
||||
mov poolActive3D,1
|
||||
mov poolPocket3D,-1
|
||||
mov poolSinkTime3D,0
|
||||
mov poolVX3D,0
|
||||
mov poolVY3D,0
|
||||
mov eax,1
|
||||
@@:
|
||||
ret
|
||||
PoolPlaceCue3D ENDP
|
||||
|
||||
PoolBallLegal3D PROC ball:DWORD
|
||||
mov ecx,ball
|
||||
xor eax,eax
|
||||
cmp ecx,15
|
||||
ja @F
|
||||
cmp ecx,pyrCue3D
|
||||
je @F
|
||||
cmp poolActive3D[ecx*4],1
|
||||
sete al
|
||||
@@:
|
||||
ret
|
||||
PoolBallLegal3D ENDP
|
||||
|
||||
PoolCountGroup3D PROC
|
||||
mov poolAtStart3D,0
|
||||
ret
|
||||
PoolCountGroup3D ENDP
|
||||
|
||||
PoolFinishShot3D PROC uses ebx esi edi
|
||||
cmp pyrSettled3D,0
|
||||
jne pyr_finish_done
|
||||
mov pyrSettled3D,1
|
||||
mov poolFoul3D,0
|
||||
mov pyrFoulReason3D,0
|
||||
mov pyrIllegalBreak3D,0
|
||||
cmp poolFirst3D,-1
|
||||
jne pyr_finish_contact
|
||||
mov pyrFoulReason3D,1
|
||||
jmp pyr_finish_foul
|
||||
pyr_finish_contact:
|
||||
cmp poolBreak3D,0
|
||||
je pyr_finish_normal
|
||||
cmp poolPotted3D,0
|
||||
jne pyr_finish_score
|
||||
mov eax,poolBreakRails3D
|
||||
mov ecx,pyrCue3D
|
||||
btr eax,ecx
|
||||
xor ebx,ebx
|
||||
pyr_finish_rail_count:
|
||||
test eax,eax
|
||||
jz @F
|
||||
lea ecx,[eax-1]
|
||||
and eax,ecx
|
||||
inc ebx
|
||||
jmp pyr_finish_rail_count
|
||||
@@:
|
||||
cmp ebx,3
|
||||
jae pyr_finish_turn
|
||||
cmp ebx,2
|
||||
jb pyr_finish_bad_break
|
||||
xor esi,esi
|
||||
pyr_finish_break_cross:
|
||||
cmp esi,pyrCue3D
|
||||
je @F
|
||||
cmp pyrHistoryCross3D[esi*4],0
|
||||
jne pyr_finish_turn
|
||||
@@:
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_finish_break_cross
|
||||
pyr_finish_bad_break:
|
||||
mov pyrFoulReason3D,2
|
||||
jmp pyr_finish_foul
|
||||
pyr_finish_normal:
|
||||
cmp poolPotted3D,0
|
||||
jne pyr_finish_score
|
||||
cmp pyrValidEnd3D,0
|
||||
jne pyr_finish_turn
|
||||
mov pyrFoulReason3D,3
|
||||
pyr_finish_foul:
|
||||
mov poolFoul3D,1
|
||||
mov eax,poolBreak3D
|
||||
mov pyrIllegalBreak3D,eax
|
||||
xor esi,esi
|
||||
pyr_finish_restore:
|
||||
bt poolPotted3D,esi
|
||||
jnc @F
|
||||
invoke PyramidRespot3D,esi
|
||||
@@:
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_finish_restore
|
||||
mov eax,poolPlayer3D
|
||||
mov pyrFouler3D,eax
|
||||
xor eax,1
|
||||
mov poolPlayer3D,eax
|
||||
mov pyrChoiceActor3D,eax
|
||||
mov poolState3D,POOL_PENALTY
|
||||
mov poolTime3D,0
|
||||
mov poolBreak3D,0
|
||||
ret
|
||||
pyr_finish_score:
|
||||
mov ebx,poolPlayer3D
|
||||
xor esi,esi
|
||||
pyr_finish_credit:
|
||||
bt poolPotted3D,esi
|
||||
jnc @F
|
||||
mov pyrOwner3D[esi*4],ebx
|
||||
inc pyrScore3D[ebx*4]
|
||||
@@:
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_finish_credit
|
||||
cmp pyrScore3D[ebx*4],8
|
||||
jb pyr_finish_aim
|
||||
mov poolWinner3D,ebx
|
||||
mov poolState3D,POOL_RESULT
|
||||
ret
|
||||
pyr_finish_turn:
|
||||
xor poolPlayer3D,1
|
||||
pyr_finish_aim:
|
||||
mov poolBreak3D,0
|
||||
mov poolState3D,POOL_AIM
|
||||
mov poolTime3D,0
|
||||
invoke PyramidSelect3D,-1
|
||||
pyr_finish_done:
|
||||
ret
|
||||
PoolFinishShot3D ENDP
|
||||
|
||||
PyramidPenalty3D PROC uses ebx ball:DWORD
|
||||
cmp poolState3D,POOL_PENALTY
|
||||
jne pyr_penalty_done
|
||||
mov ecx,ball
|
||||
cmp ecx,15
|
||||
ja pyr_penalty_done
|
||||
cmp poolActive3D[ecx*4],1
|
||||
jne pyr_penalty_done
|
||||
mov ebx,poolPlayer3D
|
||||
mov pyrOwner3D[ecx*4],ebx
|
||||
mov poolActive3D[ecx*4],0
|
||||
mov poolPocket3D[ecx*4],-2
|
||||
mov poolSinkTime3D[ecx*4],0
|
||||
mov poolVX3D[ecx*4],0
|
||||
mov poolVY3D[ecx*4],0
|
||||
inc pyrScore3D[ebx*4]
|
||||
cmp pyrScore3D[ebx*4],8
|
||||
jb @F
|
||||
mov poolWinner3D,ebx
|
||||
mov poolState3D,POOL_RESULT
|
||||
ret
|
||||
@@:
|
||||
mov poolState3D,POOL_CHOICE
|
||||
mov poolTime3D,0
|
||||
pyr_penalty_done:
|
||||
ret
|
||||
PyramidPenalty3D ENDP
|
||||
|
||||
PyramidChoice3D PROC uses ebx esi edi choice:DWORD
|
||||
cmp poolState3D,POOL_CHOICE
|
||||
jne pyr_choice_done
|
||||
cmp choice,3
|
||||
ja pyr_choice_done
|
||||
cmp choice,2
|
||||
jb pyr_choice_actor
|
||||
cmp pyrIllegalBreak3D,0
|
||||
je pyr_choice_done
|
||||
; The penalty score survives a partial re-rack.
|
||||
cmp pyrOwner3D, -1
|
||||
je @F
|
||||
mov esi,1
|
||||
pyr_rack_exchange:
|
||||
cmp pyrOwner3D[esi*4],-1
|
||||
je pyr_rack_swap
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_rack_exchange
|
||||
jmp pyr_choice_done
|
||||
pyr_rack_swap:
|
||||
mov eax,pyrOwner3D
|
||||
mov pyrOwner3D[esi*4],eax
|
||||
mov poolActive3D[esi*4],0
|
||||
mov poolPocket3D[esi*4],-2
|
||||
mov pyrOwner3D,-1
|
||||
@@:
|
||||
mov poolActive3D,1
|
||||
mov poolPocket3D,-1
|
||||
mov poolX3D,82*FP_1
|
||||
mov poolY3D,115*FP_1
|
||||
mov poolVX3D,0
|
||||
mov poolVY3D,0
|
||||
mov poolBreak3D,1
|
||||
mov pyrCue3D,0
|
||||
call PyramidRack3D
|
||||
pyr_choice_actor:
|
||||
mov eax,pyrChoiceActor3D
|
||||
test choice,1
|
||||
jz @F
|
||||
xor eax,1
|
||||
@@:
|
||||
mov poolPlayer3D,eax
|
||||
mov poolState3D,POOL_AIM
|
||||
mov poolTime3D,0
|
||||
mov pyrFineActive3D,0
|
||||
mov poolAngle3D,0
|
||||
invoke PyramidSelect3D,-1
|
||||
pyr_choice_done:
|
||||
ret
|
||||
PyramidChoice3D ENDP
|
||||
|
||||
; Center a partial base; move the apex to the base if parity requires it.
|
||||
PyramidRack3D PROC uses ebx esi edi
|
||||
local remaining:DWORD,rowCount:DWORD,startSlot:DWORD,apex:DWORD
|
||||
local apexX:DWORD,apexY:DWORD,moveApex:DWORD
|
||||
mov remaining,0
|
||||
mov apex,-1
|
||||
mov moveApex,0
|
||||
mov esi,1
|
||||
pyr_rack_count:
|
||||
cmp pyrOwner3D[esi*4],-1
|
||||
jne @F
|
||||
inc remaining
|
||||
@@:
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_rack_count
|
||||
xor ebx,ebx
|
||||
mov esi,1
|
||||
pyr_rack_row:
|
||||
lea eax,[ebx+1]
|
||||
cmp eax,remaining
|
||||
jbe @F
|
||||
mov eax,remaining
|
||||
@@:
|
||||
mov rowCount,eax
|
||||
mov ecx,ebx
|
||||
inc ecx
|
||||
sub ecx,eax
|
||||
test ecx,1
|
||||
jz pyr_rack_even
|
||||
; One apex ball joins the last row instead of creating an asymmetric base.
|
||||
dec ecx
|
||||
shr ecx,1
|
||||
mov startSlot,ecx
|
||||
imul eax,ebx,FP_1*43302/10000
|
||||
add eax,225*FP_1
|
||||
mov apexX,eax
|
||||
imul eax,ecx,5*FP_1
|
||||
imul edx,ebx,FP_1*5/2
|
||||
sub eax,edx
|
||||
add eax,115*FP_1
|
||||
mov apexY,eax
|
||||
mov moveApex,1
|
||||
inc startSlot
|
||||
jmp pyr_rack_row_balls
|
||||
pyr_rack_even:
|
||||
shr ecx,1
|
||||
mov startSlot,ecx
|
||||
pyr_rack_row_balls:
|
||||
xor edi,edi
|
||||
pyr_rack_find:
|
||||
cmp pyrOwner3D[esi*4],-1
|
||||
je pyr_rack_place
|
||||
inc esi
|
||||
cmp esi,16
|
||||
jb pyr_rack_find
|
||||
jmp pyr_rack_complete
|
||||
pyr_rack_place:
|
||||
cmp apex,-1
|
||||
jne @F
|
||||
mov apex,esi
|
||||
@@:
|
||||
imul eax,ebx,FP_1*43302/10000
|
||||
add eax,225*FP_1
|
||||
mov poolX3D[esi*4],eax
|
||||
mov eax,edi
|
||||
add eax,startSlot
|
||||
imul eax,5*FP_1
|
||||
imul ecx,ebx,FP_1*5/2
|
||||
sub eax,ecx
|
||||
add eax,115*FP_1
|
||||
mov poolY3D[esi*4],eax
|
||||
mov poolActive3D[esi*4],1
|
||||
mov poolPocket3D[esi*4],-1
|
||||
mov poolVX3D[esi*4],0
|
||||
mov poolVY3D[esi*4],0
|
||||
mov poolSinkTime3D[esi*4],0
|
||||
inc esi
|
||||
inc edi
|
||||
dec remaining
|
||||
cmp edi,rowCount
|
||||
jb pyr_rack_find
|
||||
inc ebx
|
||||
cmp remaining,0
|
||||
jne pyr_rack_row
|
||||
pyr_rack_complete:
|
||||
cmp moveApex,0
|
||||
je @F
|
||||
mov ecx,apex
|
||||
mov eax,apexX
|
||||
mov poolX3D[ecx*4],eax
|
||||
mov eax,apexY
|
||||
mov poolY3D[ecx*4],eax
|
||||
@@:
|
||||
ret
|
||||
PyramidRack3D ENDP
|
||||
254
src_graphics/russian_party.inc
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
RRPartyReset3D PROC
|
||||
cmp rrPartyCount3D,1
|
||||
jb rr_party_default
|
||||
cmp rrPartyCount3D,3
|
||||
jbe @F
|
||||
rr_party_default:
|
||||
mov rrPartyCount3D,1
|
||||
@@:
|
||||
mov ecx,rrPartyCount3D
|
||||
inc ecx
|
||||
mov rrPartySize3D,ecx
|
||||
mov eax,1
|
||||
shl eax,cl
|
||||
dec eax
|
||||
mov rrPartyAlive3D,eax
|
||||
mov rrPartyStake3D,0
|
||||
mov rrPartySettled3D,1
|
||||
mov rrPartyReloads3D,0
|
||||
ret
|
||||
RRPartyReset3D ENDP
|
||||
|
||||
RRPartyInit3D PROC
|
||||
call RRPartyReset3D
|
||||
invoke LoadAnimPack3D,OFFSET rrPartyArt3D,OFFSET rrPartyPath3D
|
||||
cmp rrPartyArt3D.frames,6
|
||||
jne rr_party_bad_art
|
||||
cmp rrPartyArt3D.imageWidth,192
|
||||
jne rr_party_bad_art
|
||||
cmp rrPartyArt3D.height,192
|
||||
je rr_party_init_done
|
||||
rr_party_bad_art:
|
||||
invoke FreeAnimPack3D,OFFSET rrPartyArt3D
|
||||
rr_party_init_done:
|
||||
mov eax,1
|
||||
ret
|
||||
RRPartyInit3D ENDP
|
||||
|
||||
RRPartySetCount3D PROC count:DWORD
|
||||
cmp count,1
|
||||
jb rr_party_count_done
|
||||
cmp count,3
|
||||
ja rr_party_count_done
|
||||
cmp rr3d_state,RR_READY
|
||||
je @F
|
||||
cmp rr3d_state,RR_WIN
|
||||
jne rr_party_count_done
|
||||
@@:
|
||||
mov eax,count
|
||||
mov rrPartyCount3D,eax
|
||||
mov rr3d_state,RR_READY
|
||||
mov rr3d_timer,0
|
||||
call RRPartyReset3D
|
||||
call ClearKeys3D
|
||||
rr_party_count_done:
|
||||
ret
|
||||
RRPartySetCount3D ENDP
|
||||
|
||||
; Called once at the initial deal, and later only when all loaded rounds are spent.
|
||||
RRLoadCylinder3D PROC uses esi
|
||||
mov rr3d_mask,0
|
||||
xor esi,esi
|
||||
rr_party_cartridge:
|
||||
invoke RandomRange3D,6
|
||||
bt rr3d_mask,eax
|
||||
jc rr_party_cartridge
|
||||
bts rr3d_mask,eax
|
||||
inc esi
|
||||
cmp esi,rr3d_bullets
|
||||
jb rr_party_cartridge
|
||||
invoke RandomRange3D,6
|
||||
mov rr3d_chamber,eax
|
||||
inc rrPartyReloads3D
|
||||
ret
|
||||
RRLoadCylinder3D ENDP
|
||||
|
||||
RRPartyWin3D PROC
|
||||
cmp rrPartySettled3D,0
|
||||
jne rr_party_win_done
|
||||
mov rrPartySettled3D,1
|
||||
mov eax,rrPartyStake3D
|
||||
imul eax,rrPartySize3D
|
||||
mov rr3d_payout,eax
|
||||
add bankroll,eax
|
||||
mov rr3d_state,RR_WIN
|
||||
invoke PlayCasinoSound3D,OFFSET soundRoundWin,0,20003h
|
||||
invoke NpcRecordRound3D,6,1
|
||||
call SaveProgress3D
|
||||
rr_party_win_done:
|
||||
ret
|
||||
RRPartyWin3D ENDP
|
||||
|
||||
RRPartyLose3D PROC
|
||||
cmp rrPartySettled3D,0
|
||||
jne rr_party_lose_done
|
||||
mov rrPartySettled3D,1
|
||||
mov rr3d_state,RR_GLITCH
|
||||
invoke NpcRecordRound3D,6,0
|
||||
call SaveProgress3D
|
||||
rr_party_lose_done:
|
||||
ret
|
||||
RRPartyLose3D ENDP
|
||||
|
||||
; No selectable target: every participant takes their own turn with the same cylinder.
|
||||
RRPartyHit3D PROC
|
||||
cmp rrPartySettled3D,0
|
||||
jne rr_party_hit_done
|
||||
mov ecx,rr3d_chamber
|
||||
btr rr3d_mask,ecx
|
||||
mov ecx,rr3d_turn
|
||||
cmp ecx,rrPartySize3D
|
||||
jae rr_party_hit_done
|
||||
btr rrPartyAlive3D,ecx
|
||||
test ecx,ecx
|
||||
jz rr_party_player_out
|
||||
cmp rrPartyAlive3D,1
|
||||
je rr_party_last_player
|
||||
mov rr3d_state,RR_DRY
|
||||
ret
|
||||
rr_party_player_out:
|
||||
call RRPartyLose3D
|
||||
ret
|
||||
rr_party_last_player:
|
||||
call RRPartyWin3D
|
||||
rr_party_hit_done:
|
||||
ret
|
||||
RRPartyHit3D ENDP
|
||||
|
||||
RRPartyNext3D PROC uses ebx
|
||||
mov ebx,rrPartySize3D
|
||||
rr_party_next_seat:
|
||||
inc rr3d_turn
|
||||
mov eax,rr3d_turn
|
||||
cmp eax,rrPartySize3D
|
||||
jb @F
|
||||
mov rr3d_turn,0
|
||||
xor eax,eax
|
||||
@@:
|
||||
bt rrPartyAlive3D,eax
|
||||
jc rr_party_next_found
|
||||
dec ebx
|
||||
jnz rr_party_next_seat
|
||||
call RRPartyLose3D
|
||||
ret
|
||||
rr_party_next_found:
|
||||
cmp rr3d_mask,0
|
||||
jne rr_party_same_cylinder
|
||||
call RRLoadCylinder3D
|
||||
mov rr3d_state,RR_LOAD
|
||||
invoke PlayCasinoSound3D,OFFSET rrLoadSound3D,0,20003h
|
||||
ret
|
||||
rr_party_same_cylinder:
|
||||
inc rr3d_chamber
|
||||
cmp rr3d_chamber,6
|
||||
jb @F
|
||||
mov rr3d_chamber,0
|
||||
@@:
|
||||
mov rr3d_state,RR_PLAYER
|
||||
cmp rr3d_turn,0
|
||||
je @F
|
||||
mov rr3d_state,RR_RAISE
|
||||
@@:
|
||||
ret
|
||||
RRPartyNext3D ENDP
|
||||
|
||||
AbortRussianRound3D PROC
|
||||
cmp rrPartySettled3D,0
|
||||
jne @F
|
||||
mov rrPartySettled3D,1
|
||||
invoke NpcRecordRound3D,6,0
|
||||
call SaveProgress3D
|
||||
@@:
|
||||
mov rr3d_state,RR_READY
|
||||
mov rr3d_timer,0
|
||||
ret
|
||||
AbortRussianRound3D ENDP
|
||||
|
||||
RRPartyInput3D PROC uses ebx
|
||||
cmp rr3d_state,RR_READY
|
||||
je rr_party_ready_keys
|
||||
cmp rr3d_state,RR_WIN
|
||||
je rr_party_mouse
|
||||
cmp rr3d_state,RR_PLAYER
|
||||
je rr_party_mouse
|
||||
jmp rr_party_mouse_exit
|
||||
rr_party_ready_keys:
|
||||
invoke Pressed3D,25h
|
||||
test eax,eax
|
||||
jz @F
|
||||
mov eax,rrPartyCount3D
|
||||
dec eax
|
||||
invoke RRPartySetCount3D,eax
|
||||
@@:
|
||||
invoke Pressed3D,27h
|
||||
test eax,eax
|
||||
jz rr_party_mouse
|
||||
mov eax,rrPartyCount3D
|
||||
inc eax
|
||||
invoke RRPartySetCount3D,eax
|
||||
rr_party_mouse:
|
||||
cmp mouseClick3D,0
|
||||
je rr_party_input_done
|
||||
cmp rr3d_state,RR_READY
|
||||
jne rr_party_mouse_start
|
||||
cmp mouseY3D,226
|
||||
jb rr_party_mouse_start
|
||||
cmp mouseY3D,239
|
||||
jae rr_party_mouse_start
|
||||
mov eax,mouseX3D
|
||||
sub eax,188
|
||||
jc rr_party_mouse_start
|
||||
cmp eax,58
|
||||
jae rr_party_mouse_start
|
||||
xor edx,edx
|
||||
mov ecx,20
|
||||
div ecx
|
||||
cmp edx,18
|
||||
jae rr_party_mouse_start
|
||||
inc eax
|
||||
invoke RRPartySetCount3D,eax
|
||||
mov mouseClick3D,0
|
||||
ret
|
||||
rr_party_mouse_start:
|
||||
cmp mouseY3D,225
|
||||
jb rr_party_mouse_exit
|
||||
cmp mouseY3D,239
|
||||
jae rr_party_mouse_exit
|
||||
cmp mouseX3D,8
|
||||
jb rr_party_mouse_exit
|
||||
cmp mouseX3D,150
|
||||
jae rr_party_mouse_exit
|
||||
mov pressedKeys3D[20h],1
|
||||
mov mouseClick3D,0
|
||||
ret
|
||||
rr_party_mouse_exit:
|
||||
cmp mouseClick3D,0
|
||||
je rr_party_input_done
|
||||
cmp mouseY3D,3
|
||||
jb rr_party_clear_mouse
|
||||
cmp mouseY3D,17
|
||||
jae rr_party_clear_mouse
|
||||
cmp mouseX3D,252
|
||||
jb rr_party_clear_mouse
|
||||
cmp mouseX3D,312
|
||||
jae rr_party_clear_mouse
|
||||
mov mouseClick3D,0
|
||||
call RequestCardExit3D
|
||||
ret
|
||||
rr_party_clear_mouse:
|
||||
mov mouseClick3D,0
|
||||
rr_party_input_done:
|
||||
ret
|
||||
RRPartyInput3D ENDP
|
||||
|
||||
include src_graphics\russian_party_render.inc
|
||||
36
src_graphics/russian_party_data.inc
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
RRPartyInit3D PROTO
|
||||
RRPartyReset3D PROTO
|
||||
RRPartySetCount3D PROTO :DWORD
|
||||
RRPartyInput3D PROTO
|
||||
RRLoadCylinder3D PROTO
|
||||
RRPartyHit3D PROTO
|
||||
RRPartyNext3D PROTO
|
||||
RRPartyWin3D PROTO
|
||||
RRPartyLose3D PROTO
|
||||
AbortRussianRound3D PROTO
|
||||
RenderRRPartyCharacters3D PROTO
|
||||
RenderRRPartyGun3D PROTO
|
||||
RenderRRPartyControls3D PROTO
|
||||
RenderRussianExit3D PROTO
|
||||
.data
|
||||
rrPartyCount3D dd 1
|
||||
rrPartySize3D dd 2
|
||||
rrPartyAlive3D dd 3
|
||||
rrPartyStake3D dd 0
|
||||
rrPartySettled3D dd 1
|
||||
rrPartyReloads3D dd 0
|
||||
rrPartyArt3D AnimPack3D <>
|
||||
rrPartyPath3D db "assets\animations\roulette\participants-v1.bin",0
|
||||
rrPartyNames3D dd OFFSET rrPartyName0,OFFSET rrPartyName1,OFFSET rrPartyName2
|
||||
rrPartyName0 db 210,206,203,223,0
|
||||
rrPartyName1 db 209,197,208,195,197,201,0
|
||||
rrPartyName2 db 195,208,200,195,206,208,200,201,0
|
||||
rrPartyCountText3D db 209,206,207,197,208,205,200,202,200,0
|
||||
rrPartyOutText3D db 194,219,193,219,203,0
|
||||
rrPartyTurnText3D db 213,206,196,0
|
||||
rrPartyAliveText3D db 206,198,200,196,192,197,210,0
|
||||
rrPartyPoolText3D db 193,192,205,202,0
|
||||
rrPartyExitText3D db 208,224,243,237,228,32,229,249,184,32,237,229,32,231,224,234,238,237,247,229,237,46,0
|
||||
rrPartyDigits3D db "1",0,"2",0,"3",0
|
||||
rrPartyX3D dd 32,232,432
|
||||
.code
|
||||
173
src_graphics/russian_party_render.inc
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
RenderRRPartyCharacters3D PROC uses ebx esi edi
|
||||
local px:DWORD,frame:DWORD,ink:DWORD
|
||||
xor ebx,ebx
|
||||
rr_party_draw_guest:
|
||||
cmp ebx,rrPartyCount3D
|
||||
jae rr_party_draw_done
|
||||
mov esi,rrPartyX3D[ebx*4]
|
||||
cmp rrPartyCount3D,2
|
||||
jne @F
|
||||
imul esi,ebx,200
|
||||
add esi,132
|
||||
@@:
|
||||
mov px,esi
|
||||
mov frame,ebx
|
||||
lea edi,[ebx+1]
|
||||
mov ink,00D7C7A4h
|
||||
bt rrPartyAlive3D,edi
|
||||
jnc rr_party_inactive
|
||||
cmp rr3d_turn,edi
|
||||
jne rr_party_draw_body
|
||||
cmp rr3d_state,RR_RAISE
|
||||
je rr_party_active_body
|
||||
cmp rr3d_state,RR_FIRE
|
||||
je rr_party_active_body
|
||||
cmp rr3d_state,RR_DRY
|
||||
jne rr_party_draw_body
|
||||
rr_party_active_body:
|
||||
add frame,3
|
||||
mov ink,00FFE09Ah
|
||||
rr_party_draw_body:
|
||||
mov animOpacity3D,255
|
||||
jmp rr_party_body
|
||||
rr_party_inactive:
|
||||
mov ink,00697873h
|
||||
cmp rr3d_turn,edi
|
||||
jne rr_party_caption
|
||||
cmp rr3d_state,RR_DRY
|
||||
jne rr_party_caption
|
||||
mov eax,700
|
||||
sub eax,rr3d_timer
|
||||
jle rr_party_caption
|
||||
imul eax,255
|
||||
xor edx,edx
|
||||
mov ecx,700
|
||||
div ecx
|
||||
mov animOpacity3D,eax
|
||||
rr_party_body:
|
||||
invoke DrawAnimSprite3D,OFFSET rrPartyArt3D,frame,px,48,176,176
|
||||
rr_party_caption:
|
||||
mov animOpacity3D,255
|
||||
lea eax,[esi+16]
|
||||
invoke DrawBuckshotText3D,eax,38,rrPartyNames3D[ebx*4],ink
|
||||
mov ecx,OFFSET rrPartyOutText3D
|
||||
bt rrPartyAlive3D,edi
|
||||
jnc @F
|
||||
mov ecx,OFFSET rrPartyAliveText3D
|
||||
cmp rr3d_state,RR_READY
|
||||
je @F
|
||||
cmp rr3d_state,RR_WIN
|
||||
je @F
|
||||
cmp rr3d_turn,edi
|
||||
jne @F
|
||||
mov ecx,OFFSET rrPartyTurnText3D
|
||||
@@:
|
||||
lea eax,[esi+16]
|
||||
invoke DrawBuckshotText3D,eax,230,ecx,ink
|
||||
inc ebx
|
||||
jmp rr_party_draw_guest
|
||||
rr_party_draw_done:
|
||||
mov animOpacity3D,255
|
||||
ret
|
||||
RenderRRPartyCharacters3D ENDP
|
||||
|
||||
; A shared tabletop revolver is passed to the highlighted seat; no extra arm layer.
|
||||
RenderRRPartyGun3D PROC uses ebx
|
||||
local target:DWORD,t:DWORD,px:DWORD,py:DWORD
|
||||
mov ebx,rr3d_turn
|
||||
dec ebx
|
||||
cmp ebx,3
|
||||
jae rr_party_gun_done
|
||||
mov eax,rrPartyX3D[ebx*4]
|
||||
cmp rrPartyCount3D,2
|
||||
jne @F
|
||||
imul eax,ebx,200
|
||||
add eax,132
|
||||
@@:
|
||||
add eax,88
|
||||
shr eax,1
|
||||
mov target,eax
|
||||
mov eax,750
|
||||
cmp rr3d_state,RR_RAISE
|
||||
jne @F
|
||||
mov eax,rr3d_timer
|
||||
cmp eax,750
|
||||
jbe @F
|
||||
mov eax,750
|
||||
@@:
|
||||
mov t,eax
|
||||
mov eax,target
|
||||
sub eax,160
|
||||
imul eax,t
|
||||
cdq
|
||||
mov ecx,750
|
||||
idiv ecx
|
||||
add eax,160
|
||||
mov px,eax
|
||||
mov eax,19
|
||||
imul eax,t
|
||||
xor edx,edx
|
||||
div ecx
|
||||
mov edx,151
|
||||
sub edx,eax
|
||||
mov py,edx
|
||||
invoke DrawRouletteSprite3D,0,px,py,98,52,0
|
||||
rr_party_gun_done:
|
||||
ret
|
||||
RenderRRPartyGun3D ENDP
|
||||
|
||||
RenderRRPartyControls3D PROC uses ebx esi
|
||||
cmp rrPartyCount3D,1
|
||||
jbe @F
|
||||
invoke DrawBuckshotText3D,244,414,OFFSET rrPartyPoolText3D,00EBD5A0h
|
||||
mov eax,rrPartyStake3D
|
||||
test eax,eax
|
||||
jnz rr_party_pool_locked
|
||||
mov eax,rr3d_bet
|
||||
rr_party_pool_locked:
|
||||
imul eax,rrPartySize3D
|
||||
invoke DrawBuckshotNumber3D,296,414,eax,00FFFFFFh
|
||||
@@:
|
||||
cmp rr3d_state,RR_READY
|
||||
jne rr_party_controls_done
|
||||
invoke DrawBuckshotText3D,280,462,OFFSET rrPartyCountText3D,00D7C7A4h
|
||||
xor ebx,ebx
|
||||
rr_party_control:
|
||||
mov esi,ebx
|
||||
imul esi,20
|
||||
add esi,188
|
||||
mov eax,0025352Dh
|
||||
mov ecx,00766B51h
|
||||
lea edx,[ebx+1]
|
||||
cmp edx,rrPartyCount3D
|
||||
jne @F
|
||||
mov eax,003D6546h
|
||||
mov ecx,00EBD5A0h
|
||||
@@:
|
||||
invoke DrawBoxBorder,esi,226,18,13,eax,ecx,1
|
||||
lea ecx,rrPartyDigits3D[ebx*2]
|
||||
lea eax,[esi*2+14]
|
||||
invoke DrawBuckshotText3D,eax,462,ecx,00EFE7D4h
|
||||
inc ebx
|
||||
cmp ebx,3
|
||||
jb rr_party_control
|
||||
rr_party_controls_done:
|
||||
ret
|
||||
RenderRRPartyControls3D ENDP
|
||||
|
||||
RenderRussianExit3D PROC
|
||||
cmp engineMode,MODE_RUSSIAN
|
||||
jne rr_party_exit_done
|
||||
cmp cardExitActive3D,0
|
||||
jne rr_party_exit_show
|
||||
cmp rr3d_state,RR_READY
|
||||
je rr_party_exit_show
|
||||
cmp rr3d_state,RR_WIN
|
||||
je rr_party_exit_show
|
||||
cmp rr3d_state,RR_PLAYER
|
||||
jne rr_party_exit_done
|
||||
rr_party_exit_show:
|
||||
call RenderCardExit3D
|
||||
rr_party_exit_done:
|
||||
ret
|
||||
RenderRussianExit3D ENDP
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
; Native roulette: one cylinder, one paid stake, cinematic states in the same window.
|
||||
.code
|
||||
FreeRussianAssets3D PROC
|
||||
invoke FreeAnimPack3D,OFFSET rrPartyArt3D
|
||||
invoke FreeAnimPack3D,OFFSET rr3d_room
|
||||
invoke FreeAnimPack3D,OFFSET rr3d_dealer
|
||||
invoke FreeAnimPack3D,OFFSET rr3d_hands
|
||||
|
|
@ -72,6 +73,8 @@ InitRussianGame3D PROC
|
|||
mov rr3d_timer, 0
|
||||
mov rr3d_payout, 0
|
||||
mov rr3d_error, 0
|
||||
mov cardExitActive3D,0
|
||||
call RRPartyInit3D
|
||||
@@:
|
||||
ret
|
||||
InitRussianGame3D ENDP
|
||||
|
|
@ -84,22 +87,19 @@ StartRussianRound3D PROC uses ebx esi
|
|||
jle rr_start_empty
|
||||
cmp eax, bankroll
|
||||
ja rr_start_empty
|
||||
cmp rr3d_bullets, 1
|
||||
jb rr_start_empty
|
||||
cmp rr3d_bullets, 3
|
||||
ja rr_start_empty
|
||||
call RRPartyReset3D
|
||||
mov eax,rr3d_bet
|
||||
mov rrPartyStake3D,eax
|
||||
mov rrPartySettled3D,0
|
||||
sub bankroll, eax
|
||||
mov rr3d_mask, 0
|
||||
mov rr3d_payout, 0
|
||||
mov rr3d_error, 0
|
||||
xor esi, esi
|
||||
rr_place_cartridge:
|
||||
invoke RandomRange3D, 6
|
||||
bt rr3d_mask, eax
|
||||
jc rr_place_cartridge
|
||||
bts rr3d_mask, eax
|
||||
inc esi
|
||||
cmp esi, rr3d_bullets
|
||||
jb rr_place_cartridge
|
||||
invoke RandomRange3D, 6
|
||||
mov rr3d_chamber, eax
|
||||
invoke RandomRange3D, 2
|
||||
call RRLoadCylinder3D
|
||||
invoke RandomRange3D, rrPartySize3D
|
||||
mov rr3d_turn, eax
|
||||
mov rr3d_state, RR_LOAD
|
||||
mov rr3d_timer, 0
|
||||
|
|
@ -163,6 +163,11 @@ rr_next_outcome:
|
|||
mov rr3d_state, RR_DRY
|
||||
ret
|
||||
rr_live_round:
|
||||
cmp rrPartyCount3D,1
|
||||
jbe @F
|
||||
call RRPartyHit3D
|
||||
ret
|
||||
@@:
|
||||
cmp rr3d_turn, 0
|
||||
je rr_player_lost
|
||||
mov eax, rr3d_bet
|
||||
|
|
@ -170,14 +175,23 @@ rr_live_round:
|
|||
mov rr3d_payout, eax
|
||||
add bankroll, eax
|
||||
mov rr3d_state, RR_WIN
|
||||
mov rrPartySettled3D,1
|
||||
invoke PlayCasinoSound3D, OFFSET soundRoundWin, 0, 20003h
|
||||
invoke NpcRecordRound3D,6,1
|
||||
call SaveProgress3D
|
||||
ret
|
||||
rr_player_lost:
|
||||
mov rrPartySettled3D,1
|
||||
mov rr3d_state, RR_GLITCH
|
||||
invoke NpcRecordRound3D,6,0
|
||||
call SaveProgress3D
|
||||
ret
|
||||
rr_next_chamber:
|
||||
cmp rrPartyCount3D,1
|
||||
jbe @F
|
||||
call RRPartyNext3D
|
||||
ret
|
||||
@@:
|
||||
inc rr3d_chamber
|
||||
cmp rr3d_chamber, 6
|
||||
jb @F
|
||||
|
|
@ -209,6 +223,14 @@ rr_next_casino:
|
|||
AdvanceRussianScene3D ENDP
|
||||
|
||||
HandleRussianInput3D PROC uses ebx
|
||||
call HandleCardExit3D
|
||||
test eax,eax
|
||||
jnz rr_input_done
|
||||
call RRPartyInput3D
|
||||
cmp cardExitActive3D,0
|
||||
jne rr_input_done
|
||||
cmp engineMode,MODE_RUSSIAN
|
||||
jne rr_input_done
|
||||
cmp rr3d_state, RR_READY
|
||||
je rr_input_ready
|
||||
cmp rr3d_state, RR_PLAYER
|
||||
|
|
@ -295,6 +317,7 @@ rr_input_next:
|
|||
jz rr_input_done
|
||||
mov rr3d_state, RR_READY
|
||||
mov rr3d_timer, 0
|
||||
call RRPartyReset3D
|
||||
rr_input_done:
|
||||
ret
|
||||
HandleRussianInput3D ENDP
|
||||
|
|
@ -542,6 +565,7 @@ RenderRussianGame3D PROC uses ebx esi edi
|
|||
cmp rr3d_state, RR_GMAN
|
||||
je rr_render_gman
|
||||
call RenderRussianTable3D
|
||||
call RenderRussianExit3D
|
||||
ret
|
||||
invoke DrawBox, 0, 0, 320, 240, 00100D17h
|
||||
invoke DrawBoxBorder, 7, 7, 306, 226, 00192320h, 00BE994Ah, 2
|
||||
|
|
@ -717,5 +741,7 @@ rr_render_return:
|
|||
rr_render_hall:
|
||||
call RenderRussianHall3D
|
||||
rr_render_done:
|
||||
call RenderRussianExit3D
|
||||
ret
|
||||
RenderRussianGame3D ENDP
|
||||
include src_graphics\russian_party.inc
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@ RenderRussianTable3D PROC uses ebx esi edi
|
|||
lea edi,screenBuffer
|
||||
mov ecx,SCREEN_SIZE
|
||||
rep movsd
|
||||
cmp rrPartyCount3D,1
|
||||
jbe rr_table_original_dealer
|
||||
call RenderRRPartyCharacters3D
|
||||
jmp rr_table_actions
|
||||
rr_table_original_dealer:
|
||||
mov eax,0
|
||||
cmp rr3d_turn,1
|
||||
jne @F
|
||||
|
|
@ -22,6 +27,7 @@ rr_table_dealer_active:
|
|||
mov eax,2
|
||||
@@:
|
||||
invoke DrawAnimSprite3D,OFFSET rr3d_dealer,eax,192,2,256,224
|
||||
rr_table_actions:
|
||||
mov eax,rr3d_state
|
||||
cmp eax,RR_LOAD
|
||||
je rr_table_load
|
||||
|
|
@ -92,6 +98,13 @@ rr_table_dry:
|
|||
mov pose,4
|
||||
mov angle,128
|
||||
rr_table_raised:
|
||||
cmp rrPartyCount3D,1
|
||||
jbe @F
|
||||
cmp rr3d_turn,0
|
||||
je @F
|
||||
call RenderRRPartyGun3D
|
||||
jmp rr_table_hud
|
||||
@@:
|
||||
cmp rr3d_turn,1
|
||||
je rr_table_dealer_gun
|
||||
; Only the player's hands/gun are visible, never a portrait of the player.
|
||||
|
|
@ -107,17 +120,45 @@ rr_table_glitch:
|
|||
rr_table_hud:
|
||||
invoke DrawBuckshotPanel3D,0,0,640,32,00111116h
|
||||
invoke DrawBuckshotText3D,14,12,OFFSET rrTitleText3D,00E9C47Ah
|
||||
invoke DrawBuckshotText3D,488,12,OFFSET bs3d_textBank,00BCBCBCh
|
||||
invoke DrawBuckshotNumber3D,540,12,bankroll,00F3E4BAh
|
||||
invoke DrawBuckshotText3D,360,12,OFFSET bs3d_textBank,00BCBCBCh
|
||||
invoke DrawBuckshotNumber3D,412,12,bankroll,00F3E4BAh
|
||||
invoke DrawBuckshotPanel3D,0,400,640,80,00111617h
|
||||
invoke DrawBuckshotText3D,16,414,OFFSET rrCartridgeText3D,00EBD5A0h
|
||||
invoke DrawBuckshotNumber3D,160,414,rr3d_bullets,00FFFFFFh
|
||||
mov ebx,rr3d_bullets
|
||||
cmp rrPartyCount3D,1
|
||||
jbe @F
|
||||
cmp rr3d_state,RR_READY
|
||||
je @F
|
||||
xor ebx,ebx
|
||||
mov edx,rr3d_mask
|
||||
rr_table_remaining_rounds:
|
||||
shr edx,1
|
||||
adc ebx,0
|
||||
test edx,edx
|
||||
jnz rr_table_remaining_rounds
|
||||
@@:
|
||||
invoke DrawBuckshotNumber3D,160,414,ebx,00FFFFFFh
|
||||
invoke DrawBuckshotText3D,456,414,OFFSET bs3d_textBet,00EBD5A0h
|
||||
invoke DrawBuckshotNumber3D,528,414,rr3d_bet,00FFFFFFh
|
||||
mov eax,rrPartyStake3D
|
||||
cmp rr3d_state,RR_READY
|
||||
je rr_table_selected_stake
|
||||
test eax,eax
|
||||
jnz rr_table_stake
|
||||
rr_table_selected_stake:
|
||||
mov eax,rr3d_bet
|
||||
rr_table_stake:
|
||||
invoke DrawBuckshotNumber3D,528,414,eax,00FFFFFFh
|
||||
mov ebx,OFFSET rrPlayerText3D
|
||||
cmp rr3d_turn,0
|
||||
je @F
|
||||
mov ebx,OFFSET rrDealerText3D
|
||||
cmp rrPartyCount3D,1
|
||||
jbe @F
|
||||
mov eax,rr3d_turn
|
||||
dec eax
|
||||
cmp eax,3
|
||||
jae @F
|
||||
mov ebx,rrPartyNames3D[eax*4]
|
||||
@@:
|
||||
cmp rr3d_state,RR_LOAD
|
||||
jne @F
|
||||
|
|
@ -131,7 +172,10 @@ rr_table_hud:
|
|||
jne @F
|
||||
mov ebx,OFFSET rrClickText3D
|
||||
@@:
|
||||
cmp rr3d_state,RR_READY
|
||||
je @F
|
||||
invoke DrawBuckshotText3D,16,440,ebx,00E9C47Ah
|
||||
@@:
|
||||
cmp rr3d_state,RR_READY
|
||||
jne rr_table_not_ready
|
||||
invoke DrawBuckshotText3D,16,440,OFFSET rrBulletKeys3D,00EBD5A0h
|
||||
|
|
@ -154,15 +198,9 @@ rr_table_not_ready:
|
|||
invoke DrawBuckshotNumber3D,184,440,rr3d_payout,007FE395h
|
||||
invoke DrawBuckshotText3D,16,462,OFFSET rrRoundText3D,00FFFFFFh
|
||||
rr_table_exit_hint:
|
||||
mov ebx,OFFSET bs3d_textPause
|
||||
cmp rr3d_state,RR_READY
|
||||
je rr_table_hall_hint
|
||||
cmp rr3d_state,RR_WIN
|
||||
jne @F
|
||||
rr_table_hall_hint:
|
||||
mov ebx,OFFSET bs3d_textExit
|
||||
@@:
|
||||
invoke DrawBuckshotText3D,530,462,ebx,00AFAFAFh
|
||||
call RenderRRPartyControls3D
|
||||
ret
|
||||
rr_table_missing:
|
||||
invoke DrawBuckshotPanel3D,0,0,640,480,00111719h
|
||||
|
|
|
|||
|
|
@ -3,3 +3,4 @@ rr3d_room AnimPack3D <>
|
|||
rr3d_dealer AnimPack3D <>
|
||||
rr3d_hands AnimPack3D <>
|
||||
rrHandsPath3D db "assets\animations\roulette\hands-v5.bin",0
|
||||
include src_graphics\russian_party_data.inc
|
||||
|
|
|
|||
|
|
@ -45,3 +45,4 @@ tableHandAnchorY3D dd 150,150,154,147,147,153,37,37
|
|||
.data?
|
||||
tableProtectedRows3D dd (640*(88+36)) dup(?)
|
||||
.code
|
||||
include src_graphics\native_blackjack_party_data.inc
|
||||
|
|
|
|||
36
tools/generators/clover_cp1251.patch
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
diff --git a/poker.asm b/poker.asm
|
||||
--- a/poker.asm
|
||||
+++ b/poker.asm
|
||||
@@ -165,1 +165,2 @@
|
||||
slotComboMults dd 32 dup(0)
|
||||
+slotComboMasks dd 32 dup(0)
|
||||
@@ -11292,1 +11293,3 @@
|
||||
mov slotComboMults[ebx * 4], edx
|
||||
+ mov ecx,maskValue
|
||||
+ mov slotComboMasks[ebx * 4],ecx
|
||||
diff --git a/casino3d.inc b/casino3d.inc
|
||||
--- a/casino3d.inc
|
||||
+++ b/casino3d.inc
|
||||
@@ -156,1 +156,2 @@
|
||||
include src_graphics\native_slots_data.inc
|
||||
+include src_graphics\native_clover_data.inc
|
||||
@@ -4730,1 +4731,4 @@
|
||||
- call BeginUnavailable3D
|
||||
+ call InitNativeClover3D
|
||||
+ test eax,eax
|
||||
+ jz target_unported
|
||||
+ mov engineMode,MODE_CLOVER
|
||||
@@ -5131,1 +5135,2 @@
|
||||
include src_graphics\native_slots.inc
|
||||
+include src_graphics\native_clover.inc
|
||||
@@ -5255,1 +5260,7 @@
|
||||
check_slots_mode:
|
||||
+ cmp engineMode,MODE_CLOVER
|
||||
+ jne @F
|
||||
+ call HandleNativeClover3D
|
||||
+ call RenderNativeClover3D
|
||||
+ jmp present_frame
|
||||
+@@:
|
||||
@@ -5485,1 +5496,2 @@
|
||||
call FreeNativeSlots3D
|
||||
+ call FreeNativeClover3D
|
||||
1289
tools/generators/generate_npc_mind.py
Normal file
52
tools/generators/npc_life_cp1251.patch
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
diff --git a/casino3d.inc b/casino3d.inc
|
||||
--- a/casino3d.inc
|
||||
+++ b/casino3d.inc
|
||||
@@ -149,1 +149,2 @@
|
||||
include src_graphics\npc_mind_data.inc
|
||||
+include src_graphics\npc_life_data.inc
|
||||
@@ -5124,1 +5125,3 @@
|
||||
include src_graphics\npc_mind.inc
|
||||
+include src_graphics\npc_life.inc
|
||||
+include src_graphics\npc_contracts.inc
|
||||
@@ -5240,1 +5243,7 @@
|
||||
check_slots_mode:
|
||||
+ cmp engineMode,MODE_NPC_DIALOG
|
||||
+ jne @F
|
||||
+ call HandleNpcDialog3D
|
||||
+ call RenderNpcDialog3D
|
||||
+ jmp present_frame
|
||||
+@@:
|
||||
diff --git a/src_graphics/hall_scene.inc b/src_graphics/hall_scene.inc
|
||||
--- a/src_graphics/hall_scene.inc
|
||||
+++ b/src_graphics/hall_scene.inc
|
||||
@@ -281,1 +281,2 @@
|
||||
call InitCasinoNpcMind
|
||||
+ call InitNpcLife3D
|
||||
@@ -624,2 +625,3 @@
|
||||
invoke HallTarget3D, 27*FP_1,25*FP_1,INTERACT_BILLIARDS,OFFSET hallPoolPrompt3D
|
||||
+ call CheckNpcInteractions3D
|
||||
ret
|
||||
@@ -640,1 +642,7 @@
|
||||
TriggerHallInteraction3D PROC
|
||||
+ cmp interactTargetId,INTERACT_NPC
|
||||
+ jne @F
|
||||
+ call OpenNpcDialog3D
|
||||
+ ret
|
||||
+@@:
|
||||
+
|
||||
@@ -1207,1 +1215,4 @@
|
||||
UpdatePatrons3D PROC uses ebx esi edi
|
||||
+ call UpdateNpcLife3D
|
||||
+ ret
|
||||
+IF 0
|
||||
@@ -1281,1 +1292,2 @@
|
||||
+ENDIF
|
||||
UpdatePatrons3D ENDP
|
||||
@@ -1284,2 +1296,3 @@
|
||||
RenderPatrons3D PROC uses esi
|
||||
- xor esi, esi
|
||||
+ call RenderNpcLife3D
|
||||
+ mov esi,8
|
||||
@@ -1291,1 +1304,1 @@
|
||||
- cmp esi, HALL_PATRON_COUNT
|
||||
+ cmp esi,12
|
||||
37
tools/generators/npc_rounds_cp1251.patch
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
diff --git a/casino3d.inc b/casino3d.inc
|
||||
--- a/casino3d.inc
|
||||
+++ b/casino3d.inc
|
||||
@@ -3128,2 +3128,3 @@
|
||||
invoke PlayCasinoSound3D, OFFSET soundRoundWin, 0, 1
|
||||
+ invoke NpcRecordRound3D,8,1
|
||||
call SaveProgress3D
|
||||
@@ -3135,2 +3136,3 @@
|
||||
invoke PlayCasinoSound3D, OFFSET soundLose, 0, 1
|
||||
+ invoke NpcRecordRound3D,8,0
|
||||
call SaveProgress3D
|
||||
@@ -3413,1 +3415,3 @@
|
||||
FinalizeSkullsGuess PROC uses ebx
|
||||
+ cmp skulls3d_state,3
|
||||
+ jne skulls_guess_done
|
||||
@@ -3423,2 +3427,4 @@
|
||||
mov skulls3d_state, 4
|
||||
invoke PlayCasinoSound3D, OFFSET soundRoundWin, 0, 1
|
||||
+ invoke NpcRecordRound3D,9,1
|
||||
+ call SaveProgress3D
|
||||
@@ -3430,3 +3436,6 @@
|
||||
mov skulls3d_state, 4
|
||||
invoke PlayCasinoSound3D, OFFSET soundLose, 0, 1
|
||||
+ invoke NpcRecordRound3D,9,0
|
||||
+ call SaveProgress3D
|
||||
+skulls_guess_done:
|
||||
ret
|
||||
@@ -4160,1 +4169,3 @@
|
||||
mov skill3d_win_amount, eax
|
||||
+ invoke NpcRecordRound3D,10,1
|
||||
+ call SaveProgress3D
|
||||
@@ -4168,3 +4179,5 @@
|
||||
mov skill3d_state, 5
|
||||
mov skill3d_timer, 0
|
||||
+ invoke NpcRecordRound3D,10,0
|
||||
+ call SaveProgress3D
|
||||
invoke PlayCasinoSound3D, OFFSET soundLose, 0, 1
|
||||
36
tools/generators/pack_blackjack_guests.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
"""Offline sprite-sheet normalization; runtime rendering remains MASM."""
|
||||
import json
|
||||
import struct
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def main():
|
||||
source = ROOT / "assets/sprites/tables/blackjack-guests-v1.png"
|
||||
image = Image.open(source).convert("RGBA")
|
||||
assert image.size == (1536, 1024)
|
||||
frames = []
|
||||
for row in range(2):
|
||||
for column in range(3):
|
||||
frame = image.crop((column * 512, row * 512, (column + 1) * 512, (row + 1) * 512))
|
||||
frame = frame.resize((160, 160), Image.Resampling.NEAREST)
|
||||
assert frame.getpixel((0, 0))[3] == 0
|
||||
assert sum(alpha >= 240 for alpha in frame.getchannel("A").get_flattened_data()) > 6000
|
||||
frames.append(frame.tobytes("raw", "BGRA"))
|
||||
data = b"".join(frames)
|
||||
path = ROOT / "assets/animations/tables/blackjack-guests-v1.bin"
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_bytes(struct.pack("<4sIIII", b"ANM1", 160, 160, 6, len(data)) + data)
|
||||
room = Image.open(ROOT / "assets/sprites/tables/blackjack-room-v1.png").convert("RGBA")
|
||||
room = room.resize((640, 480), Image.Resampling.NEAREST)
|
||||
data = room.tobytes("raw", "BGRA")
|
||||
room_path = ROOT / "assets/animations/tables/blackjack-room-v1.bin"
|
||||
room_path.write_bytes(struct.pack("<4sIIII", b"ANM1", 640, 480, 1, len(data)) + data)
|
||||
print(json.dumps({"guest_frames": 6, "size": [160, 160], "path": str(path), "room": str(room_path)}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
48
tools/generators/pack_clover_assets.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
"""Offline normalization of generated art; the game animates reels in MASM."""
|
||||
import json
|
||||
import struct
|
||||
from pathlib import Path
|
||||
from PIL import Image
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
SOURCE = ROOT / "assets/sprites/clover"
|
||||
OUTPUT = ROOT / "assets/animations/clover"
|
||||
|
||||
|
||||
def pack(name, frames):
|
||||
width, height = frames[0].size
|
||||
pixels = b"".join(frame.tobytes("raw", "BGRA") for frame in frames)
|
||||
(OUTPUT / name).write_bytes(struct.pack("<4s4I", b"ANM1", width, height,
|
||||
len(frames), len(pixels)) + pixels)
|
||||
|
||||
|
||||
def main():
|
||||
OUTPUT.mkdir(parents=True, exist_ok=True)
|
||||
cabinet = Image.open(SOURCE / "cabinet-v1.png").convert("RGBA")
|
||||
cabinet = cabinet.resize((640, 480), Image.Resampling.NEAREST)
|
||||
cabinet.putalpha(255)
|
||||
pack("cabinet-v1.bin", [cabinet])
|
||||
sheet = Image.open(SOURCE / "symbols-v1.png").convert("RGBA")
|
||||
assert 1.8 < sheet.width / sheet.height < 2.2
|
||||
frames = []
|
||||
for index in range(7):
|
||||
column, row = index % 4, index // 4
|
||||
cell = sheet.crop((round(column * sheet.width / 4), round(row * sheet.height / 2),
|
||||
round((column + 1) * sheet.width / 4), round((row + 1) * sheet.height / 2)))
|
||||
bounds = cell.getchannel("A").getbbox()
|
||||
assert bounds, f"Empty symbol {index}"
|
||||
cell = cell.crop(bounds)
|
||||
cell.thumbnail((46, 46), Image.Resampling.NEAREST)
|
||||
frame = Image.new("RGBA", (56, 56))
|
||||
frame.paste(cell, ((56 - cell.width) // 2, (56 - cell.height) // 2))
|
||||
frame.putalpha(frame.getchannel("A").point(lambda value: 255 if value >= 128 else 0))
|
||||
frames.append(frame)
|
||||
pack("symbols-v1.bin", frames)
|
||||
(OUTPUT / "manifest.json").write_text(json.dumps({"symbols": ["clover", "lemon", "cherries",
|
||||
"bell", "diamond", "chest", "seven"], "cabinet": [640, 480], "symbol": [56, 56],
|
||||
"runtime": "MASM; five reels, three complete rows, legacy additive combos"}, indent=2) + "\n")
|
||||
print("Packed Clover 5x3 cabinet and seven alpha-tested symbols")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
56
tools/generators/pack_pyramid_assets.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
"""Offline art normalization to the exact assembly table and ball anchors."""
|
||||
from pathlib import Path
|
||||
import struct
|
||||
from PIL import Image
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
SOURCE = ROOT / "assets/sprites/pyramid"
|
||||
OUT = ROOT / "assets/animations/pyramid"
|
||||
|
||||
|
||||
def pack(name, frames):
|
||||
w, h = frames[0].size
|
||||
payload = b"".join(frame.tobytes("raw", "BGRA") for frame in frames)
|
||||
(OUT / name).write_bytes(struct.pack("<4s4I", b"ANM1", w, h, len(frames), len(payload)) + payload)
|
||||
|
||||
|
||||
def main():
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
source = Image.open(SOURCE / "table-v2.png").convert("RGBA")
|
||||
# Nine-slice-style normalization keeps the mouths and cushion noses aligned
|
||||
# with the shared logical cloth rectangle, rather than scaling the whole art.
|
||||
source_x = [0, 128, 160, 723, 1290, 1320, 1448]
|
||||
source_y = [0, 197, 220, 733, 747, 1086]
|
||||
target_x = [0, 60, 61, 320, 579, 580, 640]
|
||||
target_y = [0, 100, 101, 359, 360, 480]
|
||||
frame = Image.new("RGBA", (640, 480))
|
||||
for row in range(len(target_y) - 1):
|
||||
for col in range(len(target_x) - 1):
|
||||
cell = source.crop((round(source_x[col] * source.width / 1448),
|
||||
round(source_y[row] * source.height / 1086),
|
||||
round(source_x[col + 1] * source.width / 1448),
|
||||
round(source_y[row + 1] * source.height / 1086)))
|
||||
cell = cell.resize((target_x[col + 1] - target_x[col],
|
||||
target_y[row + 1] - target_y[row]), Image.Resampling.NEAREST)
|
||||
frame.paste(cell, (target_x[col], target_y[row]))
|
||||
frame.putalpha(255)
|
||||
pack("table-v2.bin", [frame])
|
||||
sheet = Image.open(SOURCE / "balls-v1.png").convert("RGBA")
|
||||
frames = []
|
||||
for i in range(8):
|
||||
col, row = i % 4, i // 4
|
||||
cell = sheet.crop((round(col * sheet.width / 4), round(row * sheet.height / 2),
|
||||
round((col + 1) * sheet.width / 4), round((row + 1) * sheet.height / 2)))
|
||||
# Ignore faint generator fringe outside the actual circular ball.
|
||||
cell.putalpha(cell.getchannel("A").point(lambda a: 255 if a >= 192 else 0))
|
||||
cell = cell.crop(cell.getchannel("A").getbbox())
|
||||
cell.thumbnail((10, 10), Image.Resampling.LANCZOS)
|
||||
frame = Image.new("RGBA", (12, 12))
|
||||
frame.paste(cell, ((12 - cell.width) // 2, (12 - cell.height) // 2))
|
||||
frames.append(frame)
|
||||
pack("balls-v1.bin", frames)
|
||||
print("Packed anchored 640x480 table and eight 12x12 Russian ball poses")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
28
tools/generators/pack_russian_party.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
"""Offline packing of neutral seated guest artwork, not game logic."""
|
||||
import struct
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def main():
|
||||
image = Image.open(ROOT / "assets/sprites/roulette/participants-v1.png").convert("RGBA")
|
||||
assert image.size == (1536, 1024)
|
||||
frames = []
|
||||
for row in range(2):
|
||||
for col in range(3):
|
||||
frame = image.crop((col * 512, row * 512, (col + 1) * 512, (row + 1) * 512))
|
||||
frame = frame.resize((192, 192), Image.Resampling.NEAREST)
|
||||
assert frame.getpixel((0, 0))[3] == 0
|
||||
assert sum(a >= 240 for a in frame.getchannel("A").get_flattened_data()) > 8000
|
||||
frames.append(frame.tobytes("raw", "BGRA"))
|
||||
data = b"".join(frames)
|
||||
output = ROOT / "assets/animations/roulette/participants-v1.bin"
|
||||
output.write_bytes(struct.pack("<4sIIII", b"ANM1", 192, 192, 6, len(data)) + data)
|
||||
print("Packed six neutral seated guest frames for native Russian roulette")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
22
tools/generators/patch_gen.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
|
||||
with open('tools/generators/generate_npc_mind.py', 'r', encoding='utf-8') as f:
|
||||
c = f.read()
|
||||
|
||||
c = c.replace('invoke PrintStr, OFFSET chipText', 'invoke PrintStr, OFFSET mpkChipsPrefix')
|
||||
c = c.replace('invoke PrintStr, OFFSET cheatCodePrompt', 'invoke PrintStr, OFFSET mpkThoughtPrefix')
|
||||
|
||||
old_str = 'mpkWaitNextStr db 13,10,"[Нажмите любую клавишу для следующей раздачи, 0 для выхода]...",0\n'
|
||||
new_str = old_str + 'mpkChipsPrefix db " Стек: $",0\nmpkThoughtPrefix db " [Мысли]: ",0\n'
|
||||
|
||||
if old_str in c:
|
||||
c = c.replace(old_str, new_str)
|
||||
print("Added prefix strings")
|
||||
else:
|
||||
print("Target string not found in c")
|
||||
|
||||
with open('tools/generators/generate_npc_mind.py', 'w', encoding='utf-8') as f:
|
||||
f.write(c)
|
||||
|
||||
print("Saved generate_npc_mind.py")
|
||||
|
|
@ -1,92 +1,46 @@
|
|||
from pathlib import Path
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
with open(REPO_ROOT / 'poker.asm', 'r', encoding='cp1251') as f:
|
||||
# -*- coding: utf-8 -*-
|
||||
with open('poker.asm', 'r', encoding='cp1251') as f:
|
||||
text = f.read()
|
||||
|
||||
# 1. Add defaultPlayerSave
|
||||
if 'defaultPlayerSave' not in text:
|
||||
target = 'saveFileName db 64 dup(0)'
|
||||
replacement = 'saveFileName db 64 dup(0)\r\ndefaultPlayerSave db "Player.dat",0'
|
||||
text = text.replace(target, replacement, 1)
|
||||
target_str = 'pokerTitle db 13,10,"--- Poker ---",13,10,0\n'
|
||||
new_str = target_str + '''pokerModeMenuText db "1. Классический покер 1 на 1 (против Дилера)",13,10
|
||||
db "2. Стол на 4 персоны (Вы против посетителей казино)",13,10
|
||||
db "0. Выход в главное меню",13,10
|
||||
db "Выбор: ",0
|
||||
'''
|
||||
|
||||
# 2. Remove include casino3d.inc from old position
|
||||
old_inc = 'include casino3d.inc'
|
||||
if old_inc in text:
|
||||
text = text.replace(old_inc, '; include casino3d.inc moved below', 1)
|
||||
target_proc = 'GamePoker PROC\nstart_poker:\n'
|
||||
new_proc = '''GamePoker PROC
|
||||
poker_choose_mode:
|
||||
call ClearView
|
||||
invoke PrintTitleColor, OFFSET pokerTitle
|
||||
invoke PrintStr, OFFSET pokerModeMenuText
|
||||
call ReadKey
|
||||
cmp al, '1'
|
||||
je start_poker
|
||||
cmp al, '2'
|
||||
je poker_launch_multitable
|
||||
cmp al, '0'
|
||||
je poker_mode_exit
|
||||
jmp poker_choose_mode
|
||||
|
||||
# 3. Update run_casino_3d in MainMenu
|
||||
old_run_3d = """run_casino_3d:
|
||||
|
||||
call StartCasino3D
|
||||
|
||||
jmp menu_loop"""
|
||||
|
||||
new_run_3d = """run_casino_3d:
|
||||
invoke ShowWindow, hCasinoConsole, SW_HIDE
|
||||
call StartCasino3D
|
||||
invoke ShowWindow, hCasinoConsole, SW_SHOW
|
||||
invoke SetForegroundWindow, hCasinoConsole
|
||||
jmp menu_loop"""
|
||||
|
||||
if old_run_3d in text:
|
||||
text = text.replace(old_run_3d, new_run_3d, 1)
|
||||
else:
|
||||
print('Notice: old_run_3d pattern not exact, searching line-by-line')
|
||||
|
||||
# 4. Insert include casino3d.inc after MainMenu ENDP and replace main PROC
|
||||
pos = text.find('exit_menu:')
|
||||
if pos != -1:
|
||||
end_main_pos = text.find('END main')
|
||||
if end_main_pos != -1:
|
||||
new_main_block = """exit_menu:
|
||||
poker_launch_multitable:
|
||||
call GameMultiPoker
|
||||
ret
|
||||
MainMenu ENDP
|
||||
|
||||
include casino3d.inc
|
||||
poker_mode_exit:
|
||||
ret
|
||||
|
||||
; --- main: Unified Entry Point ---
|
||||
main PROC
|
||||
invoke SetConsoleOutputCP, 65001
|
||||
invoke SetConsoleCP, 65001
|
||||
invoke GetStdHandle, STD_OUTPUT_HANDLE
|
||||
mov hOut, eax
|
||||
call ConfigureConsoleSize
|
||||
call EnableAnsi
|
||||
invoke CreateDirectoryA, OFFSET runtimeDir, 0
|
||||
invoke GetStdHandle, STD_INPUT_HANDLE
|
||||
mov hIn, eax
|
||||
invoke GetTickCount
|
||||
mov seed, eax
|
||||
call InitSounds
|
||||
call InitPaths3D
|
||||
call AutoLoadAccountFast
|
||||
cmp accountCount, 0
|
||||
jne @F
|
||||
call ResetProfileDefaults
|
||||
invoke CopyCString, OFFSET saveFileName, OFFSET defaultPlayerSave
|
||||
call SaveGame
|
||||
call CollectAccounts
|
||||
@@:
|
||||
call ApplySoundVolume
|
||||
invoke GetConsoleWindow
|
||||
mov hCasinoConsole, eax
|
||||
invoke ShowWindow, hCasinoConsole, SW_HIDE
|
||||
call StartCasino3D
|
||||
cmp mutex3D, 0
|
||||
je @F
|
||||
invoke CloseHandle, mutex3D
|
||||
@@:
|
||||
invoke ExitProcess, 0
|
||||
main ENDP
|
||||
"""
|
||||
text = text[:pos] + new_main_block + '\r\nEND main\r\n'
|
||||
print('Successfully replaced main block!')
|
||||
else:
|
||||
print('Error: END main not found')
|
||||
start_poker:
|
||||
'''
|
||||
|
||||
if target_str not in text:
|
||||
print("ERROR: target_str not found")
|
||||
elif target_proc not in text:
|
||||
print("ERROR: target_proc not found")
|
||||
else:
|
||||
print('Error: exit_menu: not found')
|
||||
|
||||
with open(REPO_ROOT / 'poker.asm', 'wb') as f:
|
||||
f.write(text.encode('cp1251'))
|
||||
|
||||
print('poker.asm updated in CP1251!')
|
||||
text = text.replace(target_str, new_str, 1)
|
||||
text = text.replace(target_proc, new_proc, 1)
|
||||
with open('poker.asm', 'w', encoding='cp1251') as f:
|
||||
f.write(text)
|
||||
print("poker.asm patched successfully")
|
||||
|
|
|
|||
6
tools/generators/pyramid_cleanup_cp1251.patch
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
diff --git a/casino3d.inc b/casino3d.inc
|
||||
--- a/casino3d.inc
|
||||
+++ b/casino3d.inc
|
||||
@@ -5498,1 +5498,2 @@
|
||||
call FreeNativeClover3D
|
||||
+ call FreePyramidAssets3D
|
||||
16
tools/tests/blackjack_party_probe.asm
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
.386
|
||||
.model flat,stdcall
|
||||
option casemap:none
|
||||
include F:\MASM32\masm32\include\windows.inc
|
||||
include F:\MASM32\masm32\include\kernel32.inc
|
||||
InitPaths3D PROTO
|
||||
LoadArrivalAssets3D PROTO
|
||||
RunBJPartyTest3D PROTO
|
||||
.code
|
||||
RunBJPartyProbe PROC
|
||||
call InitPaths3D
|
||||
call LoadArrivalAssets3D
|
||||
call RunBJPartyTest3D
|
||||
invoke ExitProcess,eax
|
||||
RunBJPartyProbe ENDP
|
||||
END
|
||||
364
tools/tests/blackjack_party_test.inc
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
; Native state-machine regression. Tests never write the real player's profile.
|
||||
.data
|
||||
bjPartySeenLo dd 0
|
||||
bjPartySeenHi dd 0
|
||||
bjPartySeenCount dd 0
|
||||
bjPartyShot1 db "build\actions\blackjack-party-1.bmp",0
|
||||
bjPartyShot2 db "build\actions\blackjack-party-2.bmp",0
|
||||
bjPartyShot3 db "build\actions\blackjack-party-3.bmp",0
|
||||
bjPartyShots dd OFFSET bjPartyShot1,OFFSET bjPartyShot2,OFFSET bjPartyShot3
|
||||
bjPartyFlightShot db "build\actions\blackjack-party-flight.bmp",0
|
||||
bjPartyResultShot db "build\actions\blackjack-party-result.bmp",0
|
||||
bjPartyExitShot db "build\actions\blackjack-party-exit.bmp",0
|
||||
.code
|
||||
CheckBJPartyHand3D PROC uses ebx esi hand:DWORD,count:DWORD
|
||||
mov esi,hand
|
||||
cmp count,2
|
||||
jb bj_party_hand_bad
|
||||
cmp count,12
|
||||
ja bj_party_hand_bad
|
||||
xor ebx,ebx
|
||||
bj_party_hand_card:
|
||||
mov eax,[esi+ebx*4]
|
||||
cmp eax,52
|
||||
jae bj_party_hand_bad
|
||||
cmp eax,32
|
||||
jb bj_party_hand_low
|
||||
sub eax,32
|
||||
bts bjPartySeenHi,eax
|
||||
jc bj_party_hand_bad
|
||||
jmp bj_party_hand_next
|
||||
bj_party_hand_low:
|
||||
bts bjPartySeenLo,eax
|
||||
jc bj_party_hand_bad
|
||||
bj_party_hand_next:
|
||||
inc bjPartySeenCount
|
||||
inc ebx
|
||||
cmp ebx,count
|
||||
jb bj_party_hand_card
|
||||
xor eax,eax
|
||||
ret
|
||||
bj_party_hand_bad:
|
||||
mov eax,8104
|
||||
ret
|
||||
CheckBJPartyHand3D ENDP
|
||||
|
||||
RunBJPartyTest3D PROC uses ebx esi edi
|
||||
local rounds:DWORD,ticks:DWORD,savedBank:DWORD,savedSeed:DWORD,savedCursor:DWORD,fixtureSeed:DWORD
|
||||
mov engineMode,MODE_BLACKJACK
|
||||
mov cbBet3D,100
|
||||
mov cbBotCount3D,0
|
||||
call InitNativeBlackjack3D
|
||||
cmp cbPartyArt3D.pixels,0
|
||||
je bj_party_fail_art
|
||||
cmp cbPartyRoom3D.pixels,0
|
||||
je bj_party_fail_art
|
||||
; Real mouse selection; changing seats resets the displayed hand, not money.
|
||||
mov bankroll,10000
|
||||
mov mouseClick3D,1
|
||||
mov mouseX3D,270
|
||||
mov mouseY3D,40
|
||||
call BJPartyInput3D
|
||||
cmp cbBotCount3D,2
|
||||
jne bj_party_fail_input
|
||||
cmp mouseClick3D,0
|
||||
jne bj_party_fail_input
|
||||
cmp bankroll,10000
|
||||
jne bj_party_fail_input
|
||||
call StartNativeBlackjack3D
|
||||
invoke SetBJPartyCount3D,3
|
||||
cmp cbBotCount3D,2
|
||||
jne bj_party_fail_input
|
||||
cmp cbCursor3D,8
|
||||
jne bj_party_fail_deck
|
||||
cmp bankroll,9900
|
||||
jne bj_party_fail_wallet
|
||||
; A bot decision may see its own total and the dealer's upcard, nothing else.
|
||||
mov cbBots3D.score,16
|
||||
mov cbBots3D.count,2
|
||||
mov cbDealer3D,4
|
||||
invoke BJBotDecision3D,0
|
||||
mov savedCursor,eax
|
||||
mov cbDealer3D[4],12
|
||||
mov cbPlayer3D,51
|
||||
mov cbDeck3D[120],33
|
||||
invoke BJBotDecision3D,0
|
||||
cmp eax,savedCursor
|
||||
jne bj_party_fail_hidden
|
||||
mov cbBots3D[SIZEOF BJBot3D].score,18
|
||||
mov cbBots3D[SIZEOF BJBot3D].count,2
|
||||
invoke BJBotDecision3D,1
|
||||
cmp eax,1
|
||||
jne bj_party_fail_hidden
|
||||
mov cbBots3D[SIZEOF BJBot3D*2].score,13
|
||||
mov cbBots3D[SIZEOF BJBot3D*2].count,2
|
||||
invoke BJBotDecision3D,2
|
||||
test eax,eax
|
||||
jnz bj_party_fail_hidden
|
||||
; Natural beats a drawn 21, but a dealer natural beats a drawn guest 21.
|
||||
mov cbBotCount3D,3
|
||||
mov cbBotsSettled3D,0
|
||||
mov cbDealerScore3D,21
|
||||
mov cbDealerCount3D,2
|
||||
mov cbBots3D.score,21
|
||||
mov cbBots3D.count,2
|
||||
mov cbBots3D[SIZEOF BJBot3D].score,21
|
||||
mov cbBots3D[SIZEOF BJBot3D].count,3
|
||||
mov cbBots3D[SIZEOF BJBot3D*2].score,22
|
||||
call ResolveBJParty3D
|
||||
cmp cbBots3D.outcome,2
|
||||
jne bj_party_fail_wallet
|
||||
cmp cbBots3D[SIZEOF BJBot3D].outcome,1
|
||||
jne bj_party_fail_wallet
|
||||
cmp cbBots3D[SIZEOF BJBot3D*2].outcome,1
|
||||
jne bj_party_fail_wallet
|
||||
mov cbDealerCount3D,3
|
||||
mov cbBotsSettled3D,0
|
||||
call ResolveBJParty3D
|
||||
cmp cbBots3D.outcome,3
|
||||
jne bj_party_fail_wallet
|
||||
; Run 200 full rounds with each party size, alternating hits and doubles.
|
||||
mov edi,1
|
||||
bj_party_test_size:
|
||||
mov cbBotCount3D,edi
|
||||
mov rounds,200
|
||||
bj_party_test_round:
|
||||
mov eax,rounds
|
||||
imul eax,2137
|
||||
add eax,edi
|
||||
mov rngSeed3D,eax
|
||||
mov bankroll,10000
|
||||
mov cbState3D,CB_IDLE
|
||||
mov engineMode,MODE_BLACKJACK
|
||||
call StartNativeBlackjack3D
|
||||
mov eax,edi
|
||||
add eax,2
|
||||
shl eax,1
|
||||
cmp cbCursor3D,eax
|
||||
jne bj_party_fail_deck
|
||||
mov ticks,0
|
||||
mov deltaTime3D,50
|
||||
bj_party_test_tick:
|
||||
cmp cbState3D,CB_RESULT
|
||||
je bj_party_test_result
|
||||
cmp cbState3D,CB_PLAYER
|
||||
jne bj_party_test_handle
|
||||
mov pressedKeys3D[53h],1
|
||||
cmp cbPlayerScore3D,16
|
||||
jae @F
|
||||
mov pressedKeys3D[53h],0
|
||||
mov pressedKeys3D[48h],1
|
||||
@@:
|
||||
cmp cbPlayerCount3D,2
|
||||
jne bj_party_test_handle
|
||||
test rounds,1
|
||||
jz bj_party_test_handle
|
||||
mov pressedKeys3D[44h],1
|
||||
bj_party_test_handle:
|
||||
call HandleNativeBlackjack3D
|
||||
call ClearKeys3D
|
||||
cmp cbBotCount3D,edi
|
||||
jne bj_party_fail_input
|
||||
cmp cbCursor3D,52
|
||||
ja bj_party_fail_deck
|
||||
inc ticks
|
||||
cmp ticks,2000
|
||||
jae bj_party_fail_stuck
|
||||
jmp bj_party_test_tick
|
||||
bj_party_test_result:
|
||||
mov eax,10000
|
||||
sub eax,cbStake3D
|
||||
cmp cbOutcome3D,1
|
||||
je bj_party_expected
|
||||
add eax,cbStake3D
|
||||
cmp cbOutcome3D,2
|
||||
je bj_party_expected
|
||||
add eax,cbStake3D
|
||||
cmp cbOutcome3D,3
|
||||
jne bj_party_expected
|
||||
mov edx,cbStake3D
|
||||
shr edx,1
|
||||
add eax,edx
|
||||
bj_party_expected:
|
||||
cmp bankroll,eax
|
||||
jne bj_party_fail_wallet
|
||||
mov savedBank,eax
|
||||
invoke NativeBJSettle3D,cbOutcome3D
|
||||
mov eax,savedBank
|
||||
cmp bankroll,eax
|
||||
jne bj_party_fail_wallet
|
||||
mov bjPartySeenLo,0
|
||||
mov bjPartySeenHi,0
|
||||
mov bjPartySeenCount,0
|
||||
invoke CheckBJPartyHand3D,OFFSET cbPlayer3D,cbPlayerCount3D
|
||||
test eax,eax
|
||||
jnz bj_party_test_done
|
||||
invoke CheckBJPartyHand3D,OFFSET cbDealer3D,cbDealerCount3D
|
||||
test eax,eax
|
||||
jnz bj_party_test_done
|
||||
xor ebx,ebx
|
||||
bj_party_check_guests:
|
||||
mov esi,ebx
|
||||
imul esi,SIZEOF BJBot3D
|
||||
add esi,OFFSET cbBots3D
|
||||
cmp [esi].BJBot3D.state,BJ_BOT_DONE
|
||||
jne bj_party_fail_stuck
|
||||
cmp [esi].BJBot3D.outcome,3
|
||||
ja bj_party_fail_wallet
|
||||
invoke CheckBJPartyHand3D,esi,[esi].BJBot3D.count
|
||||
test eax,eax
|
||||
jnz bj_party_test_done
|
||||
inc ebx
|
||||
cmp ebx,edi
|
||||
jb bj_party_check_guests
|
||||
mov eax,bjPartySeenCount
|
||||
cmp cbCursor3D,eax
|
||||
jne bj_party_fail_deck
|
||||
xor ebx,ebx
|
||||
bj_party_check_prefix:
|
||||
mov eax,cbDeck3D[ebx*4]
|
||||
cmp eax,32
|
||||
jb @F
|
||||
sub eax,32
|
||||
bt bjPartySeenHi,eax
|
||||
jnc bj_party_fail_deck
|
||||
jmp bj_party_prefix_next
|
||||
@@:
|
||||
bt bjPartySeenLo,eax
|
||||
jnc bj_party_fail_deck
|
||||
bj_party_prefix_next:
|
||||
inc ebx
|
||||
cmp ebx,cbCursor3D
|
||||
jb bj_party_check_prefix
|
||||
dec rounds
|
||||
jnz bj_party_test_round
|
||||
cmp edi,3
|
||||
jne @F
|
||||
call RenderNativeBlackjack3D
|
||||
invoke WriteActionSnapshot3D,OFFSET bjPartyResultShot
|
||||
@@:
|
||||
; Actual framebuffer for each seat count, then repeat without state changes.
|
||||
mov cbState3D,CB_IDLE
|
||||
mov bankroll,10000
|
||||
call StartNativeBlackjack3D
|
||||
mov cbState3D,CB_PLAYER
|
||||
mov eax,cbInitialFlights3D
|
||||
imul eax,TABLE_FLIGHT_MS
|
||||
mov cbTimer3D,eax
|
||||
mov eax,rngSeed3D
|
||||
mov savedSeed,eax
|
||||
mov eax,cbCursor3D
|
||||
mov savedCursor,eax
|
||||
mov eax,bankroll
|
||||
mov savedBank,eax
|
||||
call RenderNativeBlackjack3D
|
||||
mov eax,edi
|
||||
dec eax
|
||||
invoke WriteActionSnapshot3D,bjPartyShots[eax*4]
|
||||
mov ebx,8
|
||||
bj_party_render_repeat:
|
||||
call RenderNativeBlackjack3D
|
||||
dec ebx
|
||||
jnz bj_party_render_repeat
|
||||
mov eax,savedSeed
|
||||
cmp rngSeed3D,eax
|
||||
jne bj_party_fail_render
|
||||
mov eax,savedCursor
|
||||
cmp cbCursor3D,eax
|
||||
jne bj_party_fail_render
|
||||
mov eax,savedBank
|
||||
cmp bankroll,eax
|
||||
jne bj_party_fail_render
|
||||
inc edi
|
||||
cmp edi,4
|
||||
jb bj_party_test_size
|
||||
; Player bust does not prematurely end or hide the other guests' turns.
|
||||
invoke FinishBJPlayer3D,1
|
||||
cmp cbState3D,CB_BOTS
|
||||
jne bj_party_fail_stuck
|
||||
; Choose a genuine deal that needs a guest card for the animation capture.
|
||||
mov fixtureSeed,1001
|
||||
bj_party_find_flight:
|
||||
mov eax,fixtureSeed
|
||||
mov rngSeed3D,eax
|
||||
mov cbState3D,CB_IDLE
|
||||
mov bankroll,10000
|
||||
call StartNativeBlackjack3D
|
||||
cmp cbPlayerScore3D,21
|
||||
je bj_party_next_fixture
|
||||
cmp cbDealerScore3D,21
|
||||
je bj_party_next_fixture
|
||||
cmp cbBots3D.score,17
|
||||
jb bj_party_flight_found
|
||||
bj_party_next_fixture:
|
||||
inc fixtureSeed
|
||||
cmp fixtureSeed,1101
|
||||
jae bj_party_fail_stuck
|
||||
jmp bj_party_find_flight
|
||||
bj_party_flight_found:
|
||||
invoke FinishBJPlayer3D,-1
|
||||
mov deltaTime3D,50
|
||||
mov cbBotTimer3D,BJ_PARTY_MS
|
||||
call UpdateBJParty3D
|
||||
cmp cbBots3D.state,BJ_BOT_FLIGHT
|
||||
jne bj_party_fail_stuck
|
||||
mov cbBotTimer3D,180
|
||||
call RenderNativeBlackjack3D
|
||||
invoke WriteActionSnapshot3D,OFFSET bjPartyFlightShot
|
||||
; Confirmation pauses bot timers; leaving counts once as player's loss.
|
||||
call RequestCardExit3D
|
||||
cmp cardExitActive3D,1
|
||||
jne bj_party_fail_input
|
||||
mov savedCursor,180
|
||||
call HandleNativeBlackjack3D
|
||||
cmp cbBotTimer3D,180
|
||||
jne bj_party_fail_input
|
||||
call RenderNativeBlackjack3D
|
||||
invoke WriteActionSnapshot3D,OFFSET bjPartyExitShot
|
||||
mov eax,bankroll
|
||||
mov savedBank,eax
|
||||
mov pressedKeys3D[59h],1
|
||||
call HandleNativeBlackjack3D
|
||||
cmp engineMode,MODE_WALK
|
||||
jne bj_party_fail_input
|
||||
mov eax,savedBank
|
||||
cmp bankroll,eax
|
||||
jne bj_party_fail_wallet
|
||||
mov engineMode,MODE_BLACKJACK
|
||||
; A result table can return to solo by keyboard, without another settlement.
|
||||
mov pressedKeys3D[30h],1
|
||||
call BJPartyInput3D
|
||||
cmp cbBotCount3D,0
|
||||
jne bj_party_fail_input
|
||||
cmp cbState3D,CB_IDLE
|
||||
jne bj_party_fail_input
|
||||
cmp cbPlayerCount3D,0
|
||||
jne bj_party_fail_input
|
||||
mov eax,savedBank
|
||||
cmp bankroll,eax
|
||||
jne bj_party_fail_wallet
|
||||
xor eax,eax
|
||||
ret
|
||||
bj_party_fail_art:
|
||||
mov eax,8101
|
||||
ret
|
||||
bj_party_fail_input:
|
||||
mov eax,8102
|
||||
ret
|
||||
bj_party_fail_wallet:
|
||||
mov eax,8103
|
||||
ret
|
||||
bj_party_fail_deck:
|
||||
mov eax,8104
|
||||
ret
|
||||
bj_party_fail_hidden:
|
||||
mov eax,8105
|
||||
ret
|
||||
bj_party_fail_stuck:
|
||||
mov eax,8106
|
||||
ret
|
||||
bj_party_fail_render:
|
||||
mov eax,8107
|
||||
bj_party_test_done:
|
||||
ret
|
||||
RunBJPartyTest3D ENDP
|
||||
|
|
@ -527,9 +527,14 @@ table_bj_expected:
|
|||
mov eax, savedBank
|
||||
cmp bankroll, eax
|
||||
jne table_fail_25
|
||||
call RunBJPartyTest3D
|
||||
test eax,eax
|
||||
jnz table_bj_party_failed
|
||||
call FreeCardTableAssets3D
|
||||
xor eax, eax
|
||||
ret
|
||||
table_bj_party_failed:
|
||||
ret
|
||||
table_fail_20:
|
||||
mov eax, 20
|
||||
ret
|
||||
|
|
@ -573,3 +578,4 @@ table_fail_33:
|
|||
mov eax, 33
|
||||
ret
|
||||
RunCardTablesTest3D ENDP
|
||||
include tools\tests\blackjack_party_test.inc
|
||||
|
|
|
|||
|
|
@ -93,8 +93,11 @@ include tools\tests\card_exit_test.inc
|
|||
include tools\tests\city_lighting_test.inc
|
||||
include tools\tests\durak_test.inc
|
||||
include tools\tests\slots_test.inc
|
||||
include tools\tests\clover_test.inc
|
||||
include tools\tests\pyramid_test.inc
|
||||
include tools\tests\coin_detail_test.inc
|
||||
include tools\tests\coin_test.inc
|
||||
include tools\tests\russian_party_test.inc
|
||||
|
||||
RunCasinoActionsTest3D PROC uses ebx esi edi
|
||||
local savedSeed:DWORD,iterations:DWORD,chamberMask:DWORD,value1:DWORD,value2:DWORD,count:DWORD
|
||||
|
|
@ -473,6 +476,11 @@ action_round_done:
|
|||
jne action_fail_12
|
||||
cmp bankroll, 0
|
||||
jne action_fail_12
|
||||
call RunRRPartyTest3D
|
||||
test eax,eax
|
||||
jz @F
|
||||
ret
|
||||
@@:
|
||||
call RunUnavailableTest3D
|
||||
test eax,eax
|
||||
jz @F
|
||||
|
|
@ -512,6 +520,11 @@ action_round_done:
|
|||
test eax,eax
|
||||
jz @F
|
||||
ret
|
||||
@@:
|
||||
call RunCloverTest3D
|
||||
test eax,eax
|
||||
jz @F
|
||||
ret
|
||||
@@:
|
||||
call RunCoinTest3D
|
||||
test eax,eax
|
||||
|
|
|
|||
61
tools/tests/check_blackjack_party.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
"""Inspect native party table captures and compare tested/shipping MASM."""
|
||||
import argparse
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageChops, ImageDraw, ImageStat
|
||||
from check_card_exit_build import Coff
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def frames():
|
||||
names = ["1", "2", "3", "flight", "result", "exit"]
|
||||
sheet = Image.new("RGB", (1280, 3 * 504), (20, 25, 29))
|
||||
draw = ImageDraw.Draw(sheet)
|
||||
signatures = []
|
||||
captured = {}
|
||||
for i, name in enumerate(names):
|
||||
path = ROOT / "build/actions" / f"blackjack-party-{name}.bmp"
|
||||
image = Image.open(path).convert("RGB")
|
||||
captured[name] = image
|
||||
assert image.size == (640, 480)
|
||||
assert len(image.getcolors(640 * 480)) > 1000, name
|
||||
assert sum(ImageStat.Stat(image.crop((0, 444, 640, 476))).stddev) > 10, name
|
||||
signatures.append(hashlib.sha256(image.tobytes()).digest())
|
||||
image.save(path.with_suffix(".png"))
|
||||
x, y = (i % 2) * 640, (i // 2) * 504
|
||||
sheet.paste(image, (x, y + 24))
|
||||
draw.text((x + 8, y + 6), f"Native blackjack: {name}", fill="white")
|
||||
assert len(set(signatures)) == len(names)
|
||||
for number, box in (("2", (248, 132, 392, 240)), ("3", (472, 132, 616, 240))):
|
||||
difference = ImageChops.difference(captured[number].crop(box), captured["1"].crop(box))
|
||||
assert sum(ImageStat.Stat(difference).mean) > 15, f"Guest {number} did not render"
|
||||
sheet.save(ROOT / "build/actions/blackjack-party-contact.png")
|
||||
print("PASS: six distinct native party-table captures, visible portraits, cards, controls and exit modal")
|
||||
|
||||
|
||||
def parity():
|
||||
tested = Coff(ROOT / "build/actions/actions-test.obj")
|
||||
shipping = Coff(ROOT / "build/graphics/poker.obj")
|
||||
for name, size in (("InitBJParty3D", 0), ("FreeBJParty3D", 0), ("DealBJParty3D", 0),
|
||||
("FinishBJPlayer3D", 4), ("BeginBJDealer3D", 0),
|
||||
("BJBotDecision3D", 4), ("UpdateBJParty3D", 0),
|
||||
("ResolveBJParty3D", 0), ("BJPartyInput3D", 0),
|
||||
("SetBJPartyCount3D", 4), ("RenderBJParty3D", 0),
|
||||
("DrawBJPartySelector3D", 0), ("DrawBJMiniCard3D", 16),
|
||||
("DrawBJMiniFlight3D", 16), ("NativeBJSettle3D", 4),
|
||||
("StartNativeBlackjack3D", 0), ("HandleNativeBlackjack3D", 0),
|
||||
("RenderNativeBlackjack3D", 0)):
|
||||
symbol = f"_{name}@{size}"
|
||||
assert tested.signature(symbol) == shipping.signature(symbol), name
|
||||
print("PASS: shipping party dealing, AI, settlement, animation and input match native-tested MASM")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--parity", action="store_true")
|
||||
args = parser.parse_args()
|
||||
frames()
|
||||
if args.parity:
|
||||
parity()
|
||||
82
tools/tests/check_clover.py
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
"""Verify real MASM Clover framebuffer captures and shipping-code parity."""
|
||||
import argparse
|
||||
import hashlib
|
||||
import struct
|
||||
from pathlib import Path
|
||||
from PIL import Image, ImageChops
|
||||
from check_card_exit_build import Coff
|
||||
from check_coin_detail import font, text_matches
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
OUT = ROOT / "build/actions"
|
||||
NAMES = ["clover-ready", "clover-spin", "clover-stopped", "clover-win", "clover-next", "clover-paytable"]
|
||||
FUNCTIONS = {"InitNativeClover3D": 0, "FreeNativeClover3D": 0, "StartNativeClover3D": 0,
|
||||
"CloverEvaluate3D": 0, "SettleNativeClover3D": 0, "CloverEscape3D": 0,
|
||||
"CloverReelPosition3D": 4, "HandleNativeClover3D": 0,
|
||||
"DrawCloverSymbol3D": 12, "DrawCloverReel3D": 4, "RenderNativeClover3D": 0,
|
||||
"CloverComboText3D": 4, "DrawSlotTotals3D": 12, "EvaluateSlotCombos": 0,
|
||||
"SlotApplyWin": 12, "CardTableEscape3D": 0, "TableBusy3D": 0}
|
||||
|
||||
|
||||
def main(parity=False):
|
||||
packs = ROOT / "assets/animations/clover"
|
||||
raw = (packs / "cabinet-v1.bin").read_bytes()
|
||||
assert struct.unpack_from("<4s4I", raw) == (b"ANM1", 640, 480, 1, 640 * 480 * 4)
|
||||
assert set(raw[23::4]) == {255}
|
||||
cabinet = Image.frombytes("RGBA", (640, 480), raw[20:], "raw", "BGRA").convert("RGB")
|
||||
raw = (packs / "symbols-v1.bin").read_bytes()
|
||||
stride = 56 * 56 * 4
|
||||
assert struct.unpack_from("<4s4I", raw) == (b"ANM1", 56, 56, 7, stride * 7)
|
||||
assert len(raw) == 20 + stride * 7
|
||||
assert set(raw[23::4]) == {0, 255}
|
||||
assert len({hashlib.sha256(raw[20 + i * stride:20 + (i + 1) * stride]).digest()
|
||||
for i in range(7)}) == 7
|
||||
frames = {}
|
||||
for name in NAMES:
|
||||
frame = Image.open(OUT / (name + ".bmp")).convert("RGB")
|
||||
assert frame.size == (640, 480)
|
||||
assert len(frame.getcolors(640 * 480)) > 2000, name
|
||||
frames[name] = frame
|
||||
frame.save(OUT / (name + ".png"))
|
||||
if name == "clover-paytable":
|
||||
continue
|
||||
difference = ImageChops.difference(frame, cabinet)
|
||||
for y in range(80, 318):
|
||||
for x in range(110, 530):
|
||||
in_reel = 126 <= y < 294 and any(left <= x < left + 56 for left in (144, 216, 288, 360, 432))
|
||||
if not in_reel:
|
||||
assert difference.getpixel((x, y)) == (0, 0, 0), (name, x, y)
|
||||
assert len({hashlib.sha256(frame.tobytes()).digest() for frame in frames.values()}) == len(NAMES)
|
||||
# Every complete cell contains a symbol, not a truncated or empty partial row.
|
||||
for col in (144, 216, 288, 360, 432):
|
||||
for top in (126, 182, 238):
|
||||
cell = frames["clover-ready"].crop((col + 4, top + 4, col + 52, top + 52))
|
||||
assert len(cell.getcolors(48 * 48)) > 20, (col, top)
|
||||
selected = ImageChops.difference(frames["clover-win"], frames["clover-next"])
|
||||
assert selected.crop((144, 126, 488, 294)).getbbox(), "Changing the paid combo must change the highlighted cells"
|
||||
contact = Image.new("RGB", (1920, 960))
|
||||
for i, name in enumerate(NAMES):
|
||||
contact.paste(frames[name], ((i % 3) * 640, (i // 3) * 480))
|
||||
contact.save(OUT / "clover-contact.png")
|
||||
glyphs = font()
|
||||
text_matches(frames["clover-ready"], "КЛЕВЕР 5x3", 16, 12, 2, (232, 215, 173), glyphs)
|
||||
text_matches(frames["clover-win"], "27300", 384, 402, 2, (244, 243, 232), glyphs)
|
||||
text_matches(frames["clover-win"], "+27200", 384, 422, 2, (168, 221, 185), glyphs)
|
||||
text_matches(frames["clover-win"], "ДЖЕКПОТ", 144, 350, 2, (244, 243, 232), glyphs)
|
||||
text_matches(frames["clover-next"], "ГЛАЗ", 144, 350, 2, (244, 243, 232), glyphs)
|
||||
source = (ROOT / "src_graphics/native_clover.inc").read_text(encoding="ascii")
|
||||
assert "call EvaluateSlotCombos" in source
|
||||
assert "call GameSlot" not in source and "call PaySlotMultiplier" not in source
|
||||
if parity:
|
||||
tested = Coff(ROOT / "build/actions/actions-test.obj")
|
||||
shipped = Coff(ROOT / "build/graphics/poker.obj")
|
||||
for name, size in FUNCTIONS.items():
|
||||
assert tested.signature(f"_{name}@{size}") == shipped.signature(f"_{name}@{size}"), name
|
||||
print("PASS: 5x3 complete cells, 7 real sprites, clipping, six distinct native frames, paid-mask selection" +
|
||||
(", tested/shipping ASM parity" if parity else ""))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--parity", action="store_true")
|
||||
main(parser.parse_args().parity)
|
||||
|
|
@ -4,6 +4,7 @@ import hashlib
|
|||
import json
|
||||
import re
|
||||
import struct
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
|
|
@ -14,12 +15,93 @@ ORDER = [0, 32, 15, 19, 4, 21, 2, 25, 17, 34, 6, 27, 13, 36, 11, 30,
|
|||
8, 23, 10, 5, 24, 16, 33, 1, 20, 14, 31, 9, 22, 18, 29, 7, 28,
|
||||
12, 35, 3, 26]
|
||||
RED = {1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36}
|
||||
DIGITS = ((7, 5, 5, 5, 7), (2, 6, 2, 2, 7), (7, 1, 7, 4, 7),
|
||||
(7, 1, 7, 1, 7), (5, 5, 7, 1, 1), (7, 4, 7, 1, 7),
|
||||
(7, 4, 7, 5, 7), (7, 1, 2, 2, 2), (7, 5, 7, 5, 7),
|
||||
(7, 5, 7, 1, 7))
|
||||
LABEL_INK = (255, 248, 222)
|
||||
|
||||
|
||||
@lru_cache(maxsize=2)
|
||||
def lookup_table(name):
|
||||
lines = (ROOT / "casino3d_data.inc").read_text(encoding="cp1251").splitlines()
|
||||
start = next(i for i, line in enumerate(lines) if line.startswith(name + " dd "))
|
||||
values = []
|
||||
for i, line in enumerate(lines[start:]):
|
||||
if i and not line.strip().startswith("dd "):
|
||||
break
|
||||
for value in re.findall(r"([0-9A-F]+)h", line):
|
||||
number = int(value, 16)
|
||||
values.append(number if number < 2**31 else number - 2**32)
|
||||
assert len(values) == 512, name
|
||||
return values
|
||||
|
||||
|
||||
def divide_signed(number, denominator):
|
||||
return number // denominator if number >= 0 else -((-number) // denominator)
|
||||
|
||||
|
||||
def label_positions(center_x, center_y, radius_x, radius_y, angle):
|
||||
cosine, sine = lookup_table("tableCos"), lookup_table("tableSin")
|
||||
return [(center_x + divide_signed((cosine[(i * 512 // 37 + angle) % 512] * 195 >> 16)
|
||||
* radius_x, 224),
|
||||
center_y + divide_signed((sine[(i * 512 // 37 + angle) % 512] * 195 >> 16)
|
||||
* radius_y, 224)) for i in range(37)]
|
||||
|
||||
|
||||
def value_pixels(center_x, y, number, scale):
|
||||
text = str(number)
|
||||
x = center_x - ((len(text) * 4 - 1) * scale // 2)
|
||||
return {(x + (digit_index * 4 + column) * scale + dx, y + row * scale + dy)
|
||||
for digit_index, digit in enumerate(text)
|
||||
for row, bits in enumerate(DIGITS[int(digit)])
|
||||
for column in range(3) if bits & (4 >> column)
|
||||
for dx in range(scale) for dy in range(scale)}
|
||||
|
||||
|
||||
def readable_labels():
|
||||
# Independent pixel masks check the actual assembly framebuffer, not a mock renderer.
|
||||
for angle in range(512):
|
||||
for geometry, scale in (((206, 170, 142, 46, angle), 1),
|
||||
((320, 278, 205, 88, angle), 2)):
|
||||
occupied = set()
|
||||
for number, (x, y) in zip(ORDER, label_positions(*geometry)):
|
||||
pixels = value_pixels(x, y - 5 * scale // 2, number, scale)
|
||||
assert not occupied.intersection(pixels), (angle, scale, number, "overlap")
|
||||
occupied.update(pixels)
|
||||
for name, geometry, scale in (
|
||||
("small", (206, 170, 142, 46, 0), 1),
|
||||
("rotated", (320, 278, 205, 88, 113), 2)):
|
||||
frame = Image.open(ROOT / "build/actions" / f"wheel-label-{name}.bmp").convert("RGB")
|
||||
expected = set()
|
||||
for number, (x, y) in zip(ORDER, label_positions(*geometry)):
|
||||
glyph = value_pixels(x, y - 5 * scale // 2, number, scale)
|
||||
assert not expected.intersection(glyph), (name, number, "overlapping digits")
|
||||
expected.update(glyph)
|
||||
actual = {(x, y) for y in range(480) for x in range(640)
|
||||
if frame.getpixel((x, y)) == LABEL_INK}
|
||||
assert actual == expected, (name, "missing or distorted digit pixels",
|
||||
len(expected - actual), len(actual - expected))
|
||||
|
||||
positions = label_positions(320, 278, 205, 88, 0)
|
||||
for result in range(37):
|
||||
frame = Image.open(ROOT / "build/actions" / f"wheel-label-{result:02}.bmp").convert("RGB")
|
||||
for number, (x, y) in zip(ORDER, positions):
|
||||
pixels = value_pixels(x, y - 5, number, 2)
|
||||
missing = [point for point in pixels if frame.getpixel(point) != LABEL_INK]
|
||||
assert not missing, (result, number, "ball/highlight obscures label", missing[:5])
|
||||
ink = (244, 231, 200) if result not in RED else (255, 180, 173)
|
||||
assert all(frame.getpixel(point) == ink
|
||||
for point in value_pixels(320, 268, result, 6)), (result, "central result")
|
||||
print("PASS: all 37 native results retain every upright pocket digit and large central result;")
|
||||
print(" exact 1x/2x native glyphs and no overlap at any of 512 rotation angles")
|
||||
|
||||
|
||||
def assets():
|
||||
manifest = json.loads((ROOT / "assets/animations/wheel/manifest-v1.json").read_text())
|
||||
assert manifest == {"order": ORDER, "zero_pockets": 1}
|
||||
source = (ROOT / "src_graphics/native_wheel_data.inc").read_text(encoding="ascii")
|
||||
assert 'wheelRotorPath3D db "assets\\animations\\wheel\\rotor-v2.bin",0' in source
|
||||
order = re.search(r"wheelOrder3D dd ([0-9,]+)", source).group(1)
|
||||
assert [int(value) for value in order.split(",")] == ORDER
|
||||
low, high = re.search(r"wheelRedMask3D dd ([0-9A-F]+)h,([0-9A-F]+)h", source).groups()
|
||||
|
|
@ -33,6 +115,9 @@ def assets():
|
|||
assert len(data) == 20 + size[0] * size[1] * 4, name
|
||||
alpha = set(data[23::4])
|
||||
assert alpha == ({0, 255} if name == "rotor" else {255}), name
|
||||
if name == "rotor":
|
||||
assert not any(data[i + 2] > 245 and data[i + 1] > 225 and data[i] > 185
|
||||
for i in range(20, len(data), 4)), "Baked-in numbers returned"
|
||||
print("PASS: three valid packs; exact European order, one zero and correct red/black colors")
|
||||
|
||||
|
||||
|
|
@ -65,7 +150,8 @@ def parity():
|
|||
("WheelEscape3D", 0), ("WheelTravel3D", 12),
|
||||
("DrawNativeWheelDisc3D", 20), ("RenderWheelScene3D", 0),
|
||||
("LoadNativeWheelArt3D", 0), ("FreeNativeWheelArt3D", 0),
|
||||
("DrawWheelDigit3D", 20), ("DrawWheelValue3D", 20), ("DrawWheelLabels3D", 20),
|
||||
("DrawWheelBox3D", 20), ("DrawWheelDigit3D", 20),
|
||||
("DrawWheelValue3D", 20), ("DrawWheelLabels3D", 20),
|
||||
("AnimateCityPedestrians3D", 0), ("HandleArrival3D", 0))
|
||||
for name, arguments in functions:
|
||||
symbol = f"_{name}@{arguments}"
|
||||
|
|
@ -81,5 +167,6 @@ if __name__ == "__main__":
|
|||
assets()
|
||||
if not options.assets_only:
|
||||
captures()
|
||||
readable_labels()
|
||||
if options.parity:
|
||||
parity()
|
||||
|
|
|
|||
55
tools/tests/check_npc_life.py
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
"""Inspect actual MASM dialog frames and compare tested/shipping NPC procedures."""
|
||||
import argparse
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
from check_card_exit_build import Coff
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def captures():
|
||||
sheet = Image.new("RGB", (640, 3 * 504), (20, 25, 29))
|
||||
draw = ImageDraw.Draw(sheet)
|
||||
hashes = []
|
||||
for index, name in enumerate(("open", "ready", "done")):
|
||||
path = ROOT / "build/actions" / f"npc-dialog-{name}.bmp"
|
||||
frame = Image.open(path).convert("RGB")
|
||||
assert frame.size == (640, 480)
|
||||
assert len(frame.getcolors(640 * 480)) > 1000, name
|
||||
assert frame.getpixel((60, 96)) == (186, 153, 85), "dialog border"
|
||||
hashes.append(hashlib.sha256(frame.crop((60, 96, 580, 398)).tobytes()).digest())
|
||||
frame.save(path.with_suffix(".png"))
|
||||
sheet.paste(frame, (0, index * 504 + 24))
|
||||
draw.text((8, index * 504 + 6), name, fill="white")
|
||||
assert len(set(hashes)) == 3, "Contract status/reward must visibly change"
|
||||
sheet.save(ROOT / "build/actions/npc-dialog-contact.png")
|
||||
print("PASS: three distinct native NPC dialog frames, bounded modal and changing contract status")
|
||||
|
||||
|
||||
def parity():
|
||||
tested = Coff(ROOT / "build/actions/actions-test.obj")
|
||||
shipped = Coff(ROOT / "build/graphics/poker.obj")
|
||||
procedures = (("InitNpcLife3D", 0), ("UpdateNpcLife3D", 0), ("RenderNpcLife3D", 0),
|
||||
("NpcPlanPath3D", 8), ("NpcTryCell3D", 8), ("NpcMove3D", 8),
|
||||
("NpcCanStep3D", 12), ("CheckNpcInteractions3D", 0),
|
||||
("OpenNpcDialog3D", 0), ("HandleNpcDialog3D", 0),
|
||||
("RenderNpcDialog3D", 0), ("CloseNpcDialog3D", 0),
|
||||
("NpcContractType3D", 4), ("NpcAcceptContract3D", 4),
|
||||
("NpcClaimContract3D", 4), ("NpcRecordRound3D", 8),
|
||||
("NpcSaveJournal3D", 0), ("NpcNameText3D", 4),
|
||||
("AnimateCityPedestrians3D", 0), ("FinalizeSkullsGuess", 0))
|
||||
for name, size in procedures:
|
||||
symbol = f"_{name}@{size}"
|
||||
assert tested.signature(symbol) == shipped.signature(symbol), name
|
||||
print("PASS: shipping NPC navigation, poses, dialogs, rewards and street movement match tested MASM")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--parity", action="store_true")
|
||||
args = parser.parse_args()
|
||||
captures()
|
||||
if args.parity:
|
||||
parity()
|
||||
56
tools/tests/check_russian_party.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
"""Check actual native Russian-roulette party frames and shipping code parity."""
|
||||
import argparse
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageDraw, ImageStat
|
||||
from check_card_exit_build import Coff
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def frames():
|
||||
names = ["ready", "turn", "out", "win", "exit"]
|
||||
sheet = Image.new("RGB", (1280, 3 * 504), (20, 25, 29))
|
||||
draw = ImageDraw.Draw(sheet)
|
||||
signatures = []
|
||||
for i, name in enumerate(names):
|
||||
path = ROOT / "build/actions" / f"rr-party-{name}.bmp"
|
||||
image = Image.open(path).convert("RGB")
|
||||
assert image.size == (640, 480)
|
||||
assert len(image.getcolors(640 * 480)) > 1000, name
|
||||
assert sum(ImageStat.Stat(image.crop((0, 400, 640, 480))).stddev) > 5, name
|
||||
signatures.append(hashlib.sha256(image.tobytes()).digest())
|
||||
image.save(path.with_suffix(".png"))
|
||||
x, y = (i % 2) * 640, (i // 2) * 504
|
||||
sheet.paste(image, (x, y + 24))
|
||||
draw.text((x + 8, y + 6), f"Native Russian party: {name}", fill="white")
|
||||
assert len(set(signatures)) == len(names)
|
||||
sheet.save(ROOT / "build/actions/rr-party-contact.png")
|
||||
print("PASS: five distinct native party frames: setup, active seat, elimination, win and exit dialog")
|
||||
|
||||
|
||||
def parity():
|
||||
tested = Coff(ROOT / "build/actions/actions-test.obj")
|
||||
shipping = Coff(ROOT / "build/graphics/poker.obj")
|
||||
procedures = (("RRPartyInit3D", 0), ("RRPartyReset3D", 0), ("RRPartySetCount3D", 4),
|
||||
("RRPartyInput3D", 0), ("RRLoadCylinder3D", 0), ("RRPartyHit3D", 0),
|
||||
("RRPartyNext3D", 0), ("RRPartyWin3D", 0), ("RRPartyLose3D", 0),
|
||||
("AbortRussianRound3D", 0), ("RenderRRPartyCharacters3D", 0),
|
||||
("RenderRRPartyGun3D", 0), ("RenderRRPartyControls3D", 0),
|
||||
("RenderRussianExit3D", 0), ("StartRussianRound3D", 0),
|
||||
("AdvanceRussianScene3D", 0), ("HandleRussianInput3D", 0),
|
||||
("RenderRussianGame3D", 0), ("RenderRussianTable3D", 0))
|
||||
for name, size in procedures:
|
||||
symbol = f"_{name}@{size}"
|
||||
assert tested.signature(symbol) == shipping.signature(symbol), name
|
||||
print("PASS: shipping party turns, payouts, reloading, animation and exit match native-tested MASM")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--parity", action="store_true")
|
||||
args = parser.parse_args()
|
||||
frames()
|
||||
if args.parity:
|
||||
parity()
|
||||
|
|
@ -13,7 +13,7 @@ def main():
|
|||
source = (ROOT / 'casino3d.inc').read_text(encoding='cp1251')
|
||||
interaction = source.split('Trigger3DInteraction PROC', 1)[1].split('Trigger3DInteraction ENDP', 1)[0]
|
||||
assert 'LaunchClassicGame' not in interaction
|
||||
assert interaction.count('call BeginUnavailable3D') == 7
|
||||
assert interaction.count('call BeginUnavailable3D') == 6
|
||||
assert 'call InitNativeDurak3D' in interaction
|
||||
assert 'call InitNativeSlots3D' in interaction
|
||||
panel = Image.open(OUTPUT / 'unavailable.bmp').convert('RGB')
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ def main():
|
|||
"RenderNativeSlots3D": 0, "SlotMultiplier3D": 12,
|
||||
"SettleNativeSlots3D": 0, "SlotEscape3D": 0, "SlotExitMouse3D": 0,
|
||||
"SlotReelPosition3D": 4, "DrawSlotReel3D": 4,
|
||||
"DrawSlotSymbol3D": 12, "Trigger3DInteraction": 0,
|
||||
"DrawSlotSymbol3D": 12, "DrawSlotTotals3D": 12, "Trigger3DInteraction": 0,
|
||||
"StartCasino3D": 0, "CardTableEscape3D": 0}
|
||||
for name, size in functions.items():
|
||||
symbol = f"_{name}@{size}"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import struct
|
|||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageChops
|
||||
from check_coin_detail import font, text_matches
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
OUTPUT = ROOT / "build/actions"
|
||||
|
|
@ -58,7 +59,18 @@ def main():
|
|||
for index, name in enumerate(NAMES):
|
||||
contact.paste(frames[name], ((index % 4) * 640, (index // 4) * 480))
|
||||
contact.save(OUTPUT / "slots-contact.png")
|
||||
glyphs = font()
|
||||
for name, gross, net, status, ink in (
|
||||
("slots-refund", "100", "0", "ВОЗВРАТ", (208, 212, 208)),
|
||||
("slots-net-win", "200", "+100", "ВЫПЛАТА", (168, 221, 185)),
|
||||
("slots-loss", "0", "-100", "ПРОИГРЫШ", (238, 153, 136))):
|
||||
frame = Image.open(OUTPUT / (name + ".bmp")).convert("RGB")
|
||||
text_matches(frame, gross, 384, 402, 2, (244, 243, 232), glyphs)
|
||||
text_matches(frame, net, 384, 422, 2, ink, glyphs)
|
||||
text_matches(frame, status, 208, 298, 2, (232, 215, 173), glyphs)
|
||||
frame.save(OUTPUT / (name + ".png"))
|
||||
print("PASS: 8 distinct native slot frames; pixel-accurate reel clipping; sequential stops; opaque cabinet and 8 real symbol sprites")
|
||||
print("PASS: exact native gross/net/refund/loss Russian glyphs; refund is not a net win")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
558
tools/tests/clover_fixtures.inc
Normal file
|
|
@ -0,0 +1,558 @@
|
|||
; Mechanically generated offline reference vectors.
|
||||
.data
|
||||
clpFixtureCount3D equ 553
|
||||
clpFixtures3D label DWORD
|
||||
dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,117,6,32767,1
|
||||
dd 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,78,6,32767,1
|
||||
dd 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,78,6,32767,1
|
||||
dd 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,117,6,32767,1
|
||||
dd 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,195,6,32767,1
|
||||
dd 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,195,6,32767,1
|
||||
dd 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,273,6,32767,1
|
||||
dd 6,3,6,2,6,2,5,6,4,0,6,0,3,6,6,56,1,17553,0
|
||||
dd 6,6,6,6,6,2,5,1,4,0,4,0,3,6,2,49,1,31,0
|
||||
dd 0,3,6,2,5,2,5,1,4,0,6,6,6,6,6,49,1,31744,0
|
||||
dd 0,3,6,2,5,2,6,1,6,0,6,0,3,6,6,28,1,17732,0
|
||||
dd 6,3,6,2,6,2,6,1,6,0,4,0,6,6,2,28,1,4433,0
|
||||
dd 6,6,6,6,6,2,5,1,4,0,4,0,3,6,2,49,1,31,0
|
||||
dd 0,3,6,2,5,6,6,6,6,6,4,0,3,6,2,21,1,992,0
|
||||
dd 0,3,6,2,5,2,5,1,4,0,6,6,6,6,6,49,1,31744,0
|
||||
dd 6,6,6,6,5,2,5,1,4,0,4,0,3,6,2,14,1,15,0
|
||||
dd 0,6,6,6,6,2,5,1,4,0,4,0,3,6,2,14,1,30,0
|
||||
dd 0,3,6,2,5,6,6,6,6,0,4,0,3,6,2,14,1,480,0
|
||||
dd 0,3,6,2,5,2,6,6,6,6,4,0,3,6,2,14,1,960,0
|
||||
dd 0,3,6,2,5,2,5,1,4,0,6,6,6,6,2,14,1,15360,0
|
||||
dd 0,3,6,2,5,2,5,1,4,0,4,6,6,6,6,14,1,30720,0
|
||||
dd 6,3,6,2,5,6,5,1,4,0,6,0,3,6,2,7,1,1057,0
|
||||
dd 0,6,6,2,5,2,6,1,4,0,4,6,3,6,2,7,1,2114,0
|
||||
dd 0,3,6,2,5,2,5,6,4,0,4,0,6,6,2,7,1,4228,0
|
||||
dd 0,3,6,6,5,2,5,1,6,0,4,0,3,6,2,7,1,8456,0
|
||||
dd 0,3,6,2,6,2,5,1,4,6,4,0,3,6,6,7,1,16912,0
|
||||
dd 6,3,6,2,5,2,6,1,4,0,4,0,6,6,2,7,1,4161,0
|
||||
dd 0,6,6,2,5,2,5,6,4,0,4,0,3,6,2,7,1,8322,0
|
||||
dd 0,3,6,2,5,2,5,1,6,0,4,0,3,6,6,7,1,16644,0
|
||||
dd 0,3,6,2,5,2,6,1,4,0,6,0,3,6,2,7,1,1092,0
|
||||
dd 0,3,6,6,5,2,5,6,4,0,4,6,3,6,2,7,1,2184,0
|
||||
dd 0,3,6,2,6,2,5,1,6,0,4,0,6,6,2,7,1,4368,0
|
||||
dd 6,6,6,2,5,2,5,1,4,0,4,0,3,6,2,7,1,7,0
|
||||
dd 0,6,6,6,5,2,5,1,4,0,4,0,3,6,2,7,1,14,0
|
||||
dd 0,3,6,6,6,2,5,1,4,0,4,0,3,6,2,7,1,28,0
|
||||
dd 0,3,6,2,5,6,6,6,4,0,4,0,3,6,2,7,1,224,0
|
||||
dd 0,3,6,2,5,2,6,6,6,0,4,0,3,6,2,7,1,448,0
|
||||
dd 0,3,6,2,5,2,5,6,6,6,4,0,3,6,2,7,1,896,0
|
||||
dd 0,3,6,2,5,2,5,1,4,0,6,6,6,6,2,14,1,15360,0
|
||||
dd 0,3,6,2,5,2,5,1,4,0,4,6,6,6,2,7,1,14336,0
|
||||
dd 0,3,6,2,5,2,5,1,4,0,4,0,6,6,6,7,1,28672,0
|
||||
dd 6,3,3,0,1,2,0,3,5,5,6,6,0,0,2,0,0,0,0
|
||||
dd 2,6,3,6,2,6,2,4,4,5,3,2,4,6,2,0,0,0,0
|
||||
dd 1,3,6,2,6,6,5,0,6,1,4,6,0,4,4,0,0,0,0
|
||||
dd 3,3,0,0,1,0,3,3,5,2,3,2,0,6,1,0,0,0,0
|
||||
dd 3,6,0,3,0,4,1,5,6,0,6,2,2,0,2,0,0,0,0
|
||||
dd 3,2,6,0,5,0,5,5,5,1,2,6,4,4,6,5,1,448,0
|
||||
dd 6,0,0,3,4,1,0,6,3,0,3,0,5,4,0,3,1,2114,0
|
||||
dd 5,5,4,2,1,4,4,6,3,1,6,6,1,1,1,4,2,29200,0
|
||||
dd 6,5,0,5,5,0,6,0,3,6,5,5,3,0,6,0,0,0,0
|
||||
dd 4,0,4,6,5,3,1,3,4,3,5,1,3,3,6,0,0,0,0
|
||||
dd 3,6,6,2,2,3,4,1,6,0,6,3,2,2,4,0,0,0,0
|
||||
dd 5,0,1,2,6,6,2,2,6,2,5,6,6,1,6,7,1,4368,0
|
||||
dd 4,3,1,6,3,6,6,5,5,4,1,3,3,6,2,0,0,0,0
|
||||
dd 1,3,1,2,6,3,6,4,6,6,2,2,2,5,6,9,2,24080,0
|
||||
dd 0,3,6,2,2,5,6,6,4,0,2,0,5,4,1,0,0,0,0
|
||||
dd 4,5,3,0,1,5,4,0,2,6,6,3,4,2,0,5,1,4161,0
|
||||
dd 0,1,3,1,4,3,3,3,2,6,0,0,4,6,1,3,1,224,0
|
||||
dd 3,5,6,1,4,0,2,0,2,5,6,1,3,6,4,0,0,0,0
|
||||
dd 6,1,6,6,5,6,4,0,5,4,4,3,4,5,3,0,0,0,0
|
||||
dd 2,3,2,2,4,2,0,2,6,1,1,0,3,4,3,0,0,0,0
|
||||
dd 4,3,6,6,2,3,2,6,5,3,0,2,6,2,3,7,1,4228,0
|
||||
dd 1,3,0,4,5,3,2,1,5,1,2,1,4,4,4,5,1,28672,0
|
||||
dd 1,1,3,0,1,6,5,4,1,3,0,3,0,1,2,0,0,0,0
|
||||
dd 4,5,1,2,0,2,4,0,0,5,6,0,2,0,0,0,0,0,0
|
||||
dd 6,0,2,1,5,4,0,2,0,0,1,5,5,4,0,0,0,0,0
|
||||
dd 1,6,6,6,5,6,6,2,2,0,0,2,5,3,2,7,1,14,0
|
||||
dd 6,6,6,1,6,0,5,1,3,5,3,4,5,4,5,7,1,7,0
|
||||
dd 2,6,2,0,5,1,6,6,0,4,5,0,1,1,4,0,0,0,0
|
||||
dd 1,2,5,2,0,2,3,1,2,5,6,6,1,2,4,2,1,8456,0
|
||||
dd 3,0,2,4,0,4,3,0,1,3,1,3,6,2,1,0,0,0,0
|
||||
dd 5,2,1,1,3,5,0,0,6,0,4,6,4,5,1,0,0,0,0
|
||||
dd 5,3,5,4,6,3,4,2,6,4,4,1,6,4,4,7,1,4368,0
|
||||
dd 4,4,3,6,5,3,5,0,5,0,2,0,4,6,3,0,0,0,0
|
||||
dd 3,1,2,4,2,2,4,0,5,2,4,6,0,1,1,0,0,0,0
|
||||
dd 1,4,4,4,3,4,5,2,6,4,3,6,2,5,2,5,1,14,0
|
||||
dd 0,0,6,3,3,3,6,4,2,3,0,6,6,5,1,0,0,0,0
|
||||
dd 4,2,4,0,4,4,6,0,0,1,5,4,5,2,6,0,0,0,0
|
||||
dd 0,0,4,6,4,1,3,0,0,5,2,2,1,6,1,0,0,0,0
|
||||
dd 4,6,0,2,1,6,3,3,4,1,4,4,4,2,0,5,1,7168,0
|
||||
dd 5,1,6,0,6,2,6,5,6,1,4,3,1,6,0,0,0,0,0
|
||||
dd 2,2,6,4,2,5,2,3,6,0,2,6,3,6,0,0,0,0,0
|
||||
dd 3,1,3,5,1,5,3,5,4,4,0,5,5,5,3,10,2,14472,0
|
||||
dd 0,0,6,6,4,3,2,0,6,5,2,4,3,2,4,0,0,0,0
|
||||
dd 4,1,4,3,0,1,4,4,0,6,0,4,6,1,1,0,0,0,0
|
||||
dd 5,6,0,5,2,3,2,1,3,2,4,4,5,2,4,0,0,0,0
|
||||
dd 2,4,2,6,6,1,4,2,0,5,6,5,2,4,0,2,1,4228,0
|
||||
dd 0,3,6,2,3,2,1,6,1,1,2,4,5,2,1,0,0,0,0
|
||||
dd 3,3,5,3,6,0,6,5,4,2,3,2,5,4,5,5,1,4228,0
|
||||
dd 6,6,5,1,4,4,5,6,2,2,2,4,6,4,6,0,0,0,0
|
||||
dd 6,5,5,4,6,2,4,5,4,0,2,2,1,3,5,0,0,0,0
|
||||
dd 3,2,2,4,3,2,0,1,1,5,2,1,4,6,2,0,0,0,0
|
||||
dd 6,0,1,4,3,3,4,2,0,2,1,3,4,5,0,0,0,0,0
|
||||
dd 0,2,1,4,3,4,1,5,6,1,3,2,4,3,1,0,0,0,0
|
||||
dd 6,1,2,5,0,0,0,0,3,0,3,6,3,1,4,3,1,224,0
|
||||
dd 5,0,0,5,0,1,3,6,5,3,3,3,5,6,3,0,0,0,0
|
||||
dd 1,0,1,1,4,3,3,4,6,6,0,5,1,3,6,0,0,0,0
|
||||
dd 0,1,0,4,2,3,5,5,1,2,4,3,4,2,6,0,0,0,0
|
||||
dd 4,4,1,4,4,6,1,3,4,1,5,1,2,2,2,2,1,28672,0
|
||||
dd 6,2,2,3,4,0,1,2,2,5,3,2,5,6,0,0,0,0,0
|
||||
dd 5,3,0,4,1,5,1,0,0,1,4,1,6,2,4,0,0,0,0
|
||||
dd 6,1,6,0,0,0,6,5,5,6,4,1,1,0,2,0,0,0,0
|
||||
dd 2,6,0,3,1,3,6,0,2,2,5,1,5,1,0,0,0,0,0
|
||||
dd 2,4,3,0,5,0,5,5,6,5,4,4,3,3,5,5,1,16912,0
|
||||
dd 5,3,1,3,5,6,0,1,2,2,4,2,4,4,3,0,0,0,0
|
||||
dd 4,1,1,4,4,4,0,0,6,3,5,4,1,4,0,0,0,0,0
|
||||
dd 2,0,5,3,3,5,1,1,3,5,1,3,6,5,2,0,0,0,0
|
||||
dd 3,5,5,6,4,6,6,1,1,0,5,2,2,2,1,2,1,14336,0
|
||||
dd 1,1,5,0,5,0,0,3,6,1,5,2,5,6,1,0,0,0,0
|
||||
dd 2,6,2,0,3,1,4,4,0,2,5,6,3,4,5,0,0,0,0
|
||||
dd 0,4,6,6,4,4,2,1,4,6,5,5,5,1,2,5,1,7168,0
|
||||
dd 2,5,4,2,1,2,2,6,2,4,0,0,1,4,5,0,0,0,0
|
||||
dd 3,5,2,0,3,2,2,3,2,3,0,0,0,4,2,5,2,23812,0
|
||||
dd 2,4,3,3,0,0,6,2,1,5,1,6,6,4,1,0,0,0,0
|
||||
dd 2,0,6,6,6,4,4,3,2,0,0,4,1,4,2,7,1,28,0
|
||||
dd 1,3,5,2,6,2,3,4,4,5,1,3,2,3,0,3,1,2114,0
|
||||
dd 4,3,1,2,5,0,0,5,6,5,2,3,1,3,1,0,0,0,0
|
||||
dd 0,4,2,5,1,0,2,6,0,2,1,6,2,4,5,0,0,0,0
|
||||
dd 2,0,5,6,3,3,3,6,2,1,1,4,0,2,3,0,0,0,0
|
||||
dd 3,5,5,3,5,2,0,3,2,0,2,3,2,2,2,5,2,30856,0
|
||||
dd 3,0,5,4,5,3,2,1,2,1,4,3,1,4,4,0,0,0,0
|
||||
dd 2,3,5,6,1,6,6,1,4,3,1,0,4,3,6,0,0,0,0
|
||||
dd 1,6,0,5,3,5,0,2,3,3,3,1,0,2,5,0,0,0,0
|
||||
dd 2,0,3,4,4,0,1,6,6,1,3,5,2,1,4,0,0,0,0
|
||||
dd 4,4,1,3,4,2,0,6,0,1,6,3,4,1,3,0,0,0,0
|
||||
dd 6,4,5,3,0,1,0,1,6,3,4,4,0,0,2,0,0,0,0
|
||||
dd 1,1,3,6,0,6,4,0,4,3,5,0,0,2,5,0,0,0,0
|
||||
dd 1,5,4,0,4,5,3,6,4,2,6,4,5,5,1,0,0,0,0
|
||||
dd 0,4,0,1,0,5,5,3,0,2,3,4,2,4,5,0,0,0,0
|
||||
dd 0,5,6,2,5,1,3,3,1,1,1,6,4,2,4,0,0,0,0
|
||||
dd 6,0,4,6,2,4,4,3,5,4,2,0,5,4,2,0,0,0,0
|
||||
dd 5,3,1,1,3,5,4,4,2,2,6,0,1,3,6,0,0,0,0
|
||||
dd 6,4,3,3,0,4,4,2,1,6,1,4,0,4,5,5,1,2114,0
|
||||
dd 4,4,3,0,4,0,2,1,2,5,5,5,5,2,4,5,1,7168,0
|
||||
dd 2,3,6,6,2,1,1,6,0,4,4,5,2,1,4,0,0,0,0
|
||||
dd 2,4,3,6,0,5,4,3,1,5,6,2,5,5,0,0,0,0,0
|
||||
dd 0,0,6,0,0,2,0,0,5,2,5,1,4,5,3,0,0,0,0
|
||||
dd 4,4,6,0,5,0,4,4,1,2,6,5,4,3,2,5,1,4161,0
|
||||
dd 0,5,0,4,1,5,0,3,2,3,2,3,1,0,1,0,0,0,0
|
||||
dd 6,3,3,2,3,4,1,4,1,4,1,6,0,5,0,0,0,0,0
|
||||
dd 5,0,2,2,4,2,1,1,3,3,6,6,6,4,3,7,1,7168,0
|
||||
dd 3,0,2,6,0,0,6,3,5,2,3,3,3,3,0,6,1,15360,0
|
||||
dd 5,0,0,6,3,5,0,5,4,6,3,6,0,1,6,0,0,0,0
|
||||
dd 2,5,2,5,1,1,4,4,3,4,1,1,2,2,1,0,0,0,0
|
||||
dd 5,5,1,2,4,4,3,0,4,1,4,6,3,3,0,0,0,0,0
|
||||
dd 3,2,0,2,0,0,6,6,1,5,4,2,6,5,4,0,0,0,0
|
||||
dd 6,3,0,6,6,1,5,3,0,1,3,2,6,5,1,0,0,0,0
|
||||
dd 2,1,6,0,6,3,6,1,5,4,5,3,1,6,6,0,0,0,0
|
||||
dd 4,0,0,3,1,1,6,4,5,0,4,1,6,0,6,0,0,0,0
|
||||
dd 2,4,2,3,6,0,6,0,5,3,3,1,2,0,5,0,0,0,0
|
||||
dd 1,6,1,2,2,1,4,2,6,4,1,1,2,0,2,2,1,1057,0
|
||||
dd 3,3,0,6,2,5,0,5,5,4,2,4,0,1,6,0,0,0,0
|
||||
dd 5,0,4,4,3,4,3,3,6,1,1,0,0,0,6,3,1,14336,0
|
||||
dd 5,5,4,6,2,4,0,1,6,0,3,6,0,0,5,0,0,0,0
|
||||
dd 1,6,0,4,6,2,6,2,1,0,6,1,4,6,1,0,0,0,0
|
||||
dd 3,3,6,1,2,1,3,1,5,5,0,2,2,6,0,0,0,0,0
|
||||
dd 1,0,1,1,3,4,3,3,4,2,2,1,3,2,5,0,0,0,0
|
||||
dd 0,1,4,6,1,5,4,3,4,1,1,5,3,4,3,0,0,0,0
|
||||
dd 6,5,3,0,6,4,3,1,1,3,3,6,5,6,0,3,1,1092,0
|
||||
dd 4,2,5,4,6,6,6,3,2,2,1,3,2,4,0,0,0,0,0
|
||||
dd 2,1,5,5,4,5,0,2,4,3,6,2,3,2,2,0,0,0,0
|
||||
dd 1,3,0,4,2,0,1,4,4,5,6,4,5,6,4,5,1,2184,0
|
||||
dd 3,3,4,5,4,1,0,4,5,1,3,4,3,6,0,0,0,0,0
|
||||
dd 1,6,4,6,2,1,1,2,0,0,0,6,0,3,4,0,0,0,0
|
||||
dd 0,4,5,3,4,1,1,6,2,0,6,6,2,6,6,0,0,0,0
|
||||
dd 1,5,2,1,5,1,6,4,1,0,6,4,0,6,4,0,0,0,0
|
||||
dd 0,3,6,3,0,2,1,6,1,2,6,0,3,1,1,0,0,0,0
|
||||
dd 4,0,2,3,0,2,6,4,1,3,0,6,1,4,3,0,0,0,0
|
||||
dd 0,0,5,5,4,5,1,5,2,5,2,3,6,5,2,0,0,0,0
|
||||
dd 5,5,4,1,5,5,2,5,4,6,3,1,4,6,5,0,0,0,0
|
||||
dd 6,3,3,5,1,4,6,4,0,0,2,4,0,2,4,0,0,0,0
|
||||
dd 1,2,6,2,4,5,0,4,3,0,3,0,1,3,2,0,0,0,0
|
||||
dd 0,0,5,0,3,6,5,2,4,6,1,3,4,5,0,0,0,0,0
|
||||
dd 0,4,3,4,0,0,1,5,3,5,3,2,6,5,6,0,0,0,0
|
||||
dd 5,4,6,6,2,1,3,3,1,6,1,4,5,2,0,0,0,0,0
|
||||
dd 4,4,2,1,3,5,1,4,6,6,1,2,1,5,2,0,0,0,0
|
||||
dd 0,3,1,1,5,0,2,4,4,3,0,2,0,6,5,3,1,1057,0
|
||||
dd 6,2,3,2,3,0,5,1,4,2,1,5,2,5,2,0,0,0,0
|
||||
dd 2,6,4,1,6,4,5,1,4,0,6,5,5,2,1,0,0,0,0
|
||||
dd 5,2,0,1,6,3,6,0,6,2,0,0,3,4,1,0,0,0,0
|
||||
dd 5,0,3,0,3,0,2,4,6,0,2,6,1,6,6,0,0,0,0
|
||||
dd 6,5,1,3,2,6,1,4,4,6,5,0,1,2,3,0,0,0,0
|
||||
dd 2,4,6,0,4,3,0,6,3,1,4,2,4,2,4,0,0,0,0
|
||||
dd 1,6,5,1,3,6,3,1,5,6,2,3,0,6,6,0,0,0,0
|
||||
dd 5,6,6,5,6,1,0,5,6,0,6,0,0,1,0,0,0,0,0
|
||||
dd 2,5,2,4,4,4,1,4,5,3,5,2,5,4,1,0,0,0,0
|
||||
dd 4,3,5,1,4,6,5,5,5,6,5,6,0,2,1,10,2,1476,0
|
||||
dd 5,3,6,1,6,5,2,0,6,1,0,4,6,4,1,7,1,4368,0
|
||||
dd 6,3,4,1,1,1,0,5,3,1,5,5,3,1,1,2,1,16912,0
|
||||
dd 0,3,5,5,3,6,3,1,5,4,2,5,4,3,5,5,1,16644,0
|
||||
dd 6,1,1,1,6,4,3,5,1,5,3,1,4,3,0,2,1,14,0
|
||||
dd 6,4,2,5,6,0,4,2,1,1,1,2,3,0,4,0,0,0,0
|
||||
dd 6,6,3,6,2,4,2,0,0,0,3,0,0,3,4,3,1,896,0
|
||||
dd 6,6,6,4,5,2,5,5,5,4,6,5,1,0,2,12,2,455,0
|
||||
dd 2,1,0,1,6,4,0,5,1,0,2,0,1,1,4,2,1,8456,0
|
||||
dd 5,6,4,5,2,5,5,2,1,0,0,3,5,1,0,5,1,4161,0
|
||||
dd 0,6,4,5,5,3,5,0,1,5,3,2,1,0,5,5,1,16912,0
|
||||
dd 6,2,0,0,6,6,1,6,6,2,1,2,2,4,6,0,0,0,0
|
||||
dd 0,6,3,1,3,1,5,4,1,1,6,2,4,0,4,0,0,0,0
|
||||
dd 1,1,1,1,6,2,6,0,4,1,2,3,5,5,2,4,1,15,0
|
||||
dd 4,5,1,5,0,6,6,4,6,1,0,1,4,5,5,0,0,0,0
|
||||
dd 6,3,3,4,6,6,1,6,0,2,5,2,2,5,1,0,0,0,0
|
||||
dd 6,3,5,0,1,2,1,6,6,6,0,5,0,6,6,7,1,896,0
|
||||
dd 0,2,5,1,2,4,5,0,1,0,3,2,2,2,5,2,1,14336,0
|
||||
dd 0,5,1,5,5,1,1,0,3,3,6,1,5,1,2,0,0,0,0
|
||||
dd 4,6,4,4,4,0,1,4,3,3,5,5,6,2,1,5,1,28,0
|
||||
dd 2,2,2,3,0,3,3,1,2,0,0,6,4,4,2,4,2,16647,0
|
||||
dd 2,6,5,2,0,2,6,6,4,0,5,0,5,3,5,0,0,0,0
|
||||
dd 2,4,1,2,2,5,0,4,0,4,4,5,1,5,5,0,0,0,0
|
||||
dd 0,0,3,2,4,5,5,5,4,5,0,2,4,1,5,10,2,4592,0
|
||||
dd 2,2,3,6,3,4,0,2,4,2,5,4,6,6,4,0,0,0,0
|
||||
dd 2,6,0,2,2,0,0,1,1,4,0,1,3,5,2,3,1,1092,0
|
||||
dd 2,5,4,3,1,2,4,5,0,1,6,3,2,6,5,0,0,0,0
|
||||
dd 3,3,4,1,4,4,5,5,0,0,2,3,4,4,6,0,0,0,0
|
||||
dd 3,3,0,0,2,0,5,1,0,4,0,3,1,5,4,0,0,0,0
|
||||
dd 6,2,2,3,5,4,1,3,0,0,0,0,2,5,1,0,0,0,0
|
||||
dd 1,6,2,6,4,1,0,6,6,1,1,1,0,3,3,2,1,1057,0
|
||||
dd 5,3,5,6,5,2,2,1,6,3,1,2,2,5,1,0,0,0,0
|
||||
dd 6,1,3,5,4,5,0,5,3,3,3,6,1,6,0,0,0,0,0
|
||||
dd 4,2,0,3,0,3,5,0,4,6,3,4,0,4,1,3,1,4228,0
|
||||
dd 3,5,1,5,6,3,2,1,3,4,2,5,2,6,5,0,0,0,0
|
||||
dd 0,1,0,5,5,6,0,5,0,6,4,2,0,6,1,3,1,4161,0
|
||||
dd 5,0,2,0,0,3,4,3,6,1,5,5,3,5,0,0,0,0,0
|
||||
dd 3,0,5,5,4,3,4,6,3,4,5,1,4,5,6,0,0,0,0
|
||||
dd 3,4,3,4,0,0,0,0,1,3,0,1,2,0,2,3,1,224,0
|
||||
dd 2,2,1,0,0,1,4,5,6,1,4,6,0,4,2,0,0,0,0
|
||||
dd 1,1,5,2,0,2,2,6,1,1,0,5,0,2,4,0,0,0,0
|
||||
dd 0,2,6,2,4,2,4,6,5,6,1,4,6,3,4,7,1,4228,0
|
||||
dd 6,0,3,0,3,0,2,1,0,2,0,1,6,4,4,0,0,0,0
|
||||
dd 1,2,1,4,3,6,1,4,4,5,5,6,0,3,0,0,0,0,0
|
||||
dd 6,2,3,3,3,6,0,5,1,3,4,1,5,6,3,6,2,16924,0
|
||||
dd 6,5,1,1,6,5,1,2,5,0,3,6,0,5,4,0,0,0,0
|
||||
dd 4,4,2,3,5,0,3,0,1,2,1,6,6,3,3,0,0,0,0
|
||||
dd 6,1,6,2,4,5,6,0,5,1,1,2,6,5,4,7,1,4161,0
|
||||
dd 1,3,4,0,4,6,2,5,1,5,5,2,5,2,5,0,0,0,0
|
||||
dd 1,1,4,1,6,4,2,5,1,5,4,5,6,5,6,0,0,0,0
|
||||
dd 1,5,6,2,3,1,3,3,5,2,1,1,3,2,6,2,1,1057,0
|
||||
dd 0,1,5,0,1,0,1,5,3,6,0,2,1,4,6,3,1,1057,0
|
||||
dd 0,2,1,4,1,0,0,2,6,1,1,6,4,1,2,0,0,0,0
|
||||
dd 0,4,6,0,3,6,6,4,0,6,0,3,5,3,1,0,0,0,0
|
||||
dd 2,2,5,3,1,1,1,3,3,5,2,6,6,3,6,3,1,8456,0
|
||||
dd 6,2,6,2,2,0,2,5,5,5,6,2,3,2,4,7,2,3010,0
|
||||
dd 1,6,2,3,3,1,1,5,4,0,6,0,6,1,5,0,0,0,0
|
||||
dd 2,5,4,1,4,4,2,1,3,0,5,6,4,1,3,0,0,0,0
|
||||
dd 3,5,5,6,5,1,6,5,6,4,3,0,2,4,4,0,0,0,0
|
||||
dd 5,2,0,2,3,2,0,2,5,1,4,2,5,2,6,4,2,10378,0
|
||||
dd 4,5,5,6,1,1,3,2,4,5,5,3,0,3,5,0,0,0,0
|
||||
dd 0,5,3,1,2,6,6,1,1,2,5,6,3,5,3,0,0,0,0
|
||||
dd 5,5,2,6,5,1,2,0,6,4,1,4,6,2,3,0,0,0,0
|
||||
dd 5,1,6,5,1,1,0,2,3,0,0,3,3,5,4,0,0,0,0
|
||||
dd 1,1,2,0,5,0,2,1,5,6,4,4,1,0,0,0,0,0,0
|
||||
dd 4,0,5,5,0,4,3,6,1,2,2,0,5,4,6,0,0,0,0
|
||||
dd 5,0,6,3,1,5,3,6,1,5,4,2,5,1,0,0,0,0,0
|
||||
dd 0,2,3,4,1,5,0,2,4,5,1,2,6,5,5,0,0,0,0
|
||||
dd 1,2,6,2,3,6,2,5,0,6,5,0,0,2,1,0,0,0,0
|
||||
dd 0,0,3,6,3,6,0,3,0,6,2,0,3,2,2,6,2,6342,0
|
||||
dd 6,6,6,3,2,3,6,6,3,5,3,3,5,4,2,7,1,7,0
|
||||
dd 4,2,1,6,5,4,0,3,5,5,5,0,4,6,0,0,0,0,0
|
||||
dd 1,4,0,3,2,4,6,4,6,4,4,6,1,4,0,5,1,8322,0
|
||||
dd 4,2,1,3,6,2,5,4,5,1,0,6,3,6,5,0,0,0,0
|
||||
dd 2,5,4,3,3,3,3,5,5,4,1,0,0,5,1,5,1,8322,0
|
||||
dd 1,6,0,3,6,4,0,2,5,6,5,2,3,3,6,7,1,16912,0
|
||||
dd 4,2,3,6,6,0,1,2,5,2,4,6,4,4,0,0,0,0,0
|
||||
dd 5,1,4,6,0,5,5,2,5,6,0,0,0,3,0,3,1,7168,0
|
||||
dd 4,1,3,3,5,1,4,3,1,3,6,5,4,1,5,5,1,4161,0
|
||||
dd 4,2,1,0,0,3,4,4,4,4,5,5,1,6,5,10,1,960,0
|
||||
dd 0,2,1,3,0,3,0,0,1,1,4,5,0,2,0,3,1,4161,0
|
||||
dd 6,5,1,6,3,4,4,3,5,3,0,3,4,6,6,0,0,0,0
|
||||
dd 2,3,0,1,1,5,6,4,5,4,0,5,3,1,5,0,0,0,0
|
||||
dd 6,3,6,1,1,4,3,6,2,0,2,2,1,0,2,0,0,0,0
|
||||
dd 2,3,3,0,4,3,5,3,1,3,3,0,5,2,1,0,0,0,0
|
||||
dd 2,1,0,6,1,0,4,1,3,3,5,5,3,2,2,0,0,0,0
|
||||
dd 3,2,4,0,0,2,5,3,4,1,4,3,5,3,5,0,0,0,0
|
||||
dd 1,4,6,1,5,5,3,0,2,2,6,0,4,6,6,0,0,0,0
|
||||
dd 6,5,2,6,3,4,3,1,4,4,3,1,6,3,0,0,0,0,0
|
||||
dd 1,4,3,6,0,2,2,3,6,2,3,3,0,0,5,0,0,0,0
|
||||
dd 0,2,4,1,5,6,6,2,4,5,4,1,4,6,0,0,0,0,0
|
||||
dd 1,2,1,3,0,0,3,0,5,2,2,5,6,5,6,0,0,0,0
|
||||
dd 6,6,2,0,3,0,0,0,6,1,6,3,6,4,6,3,1,224,0
|
||||
dd 0,6,5,0,3,6,4,0,4,3,0,5,0,3,0,0,0,0,0
|
||||
dd 1,3,6,6,0,3,2,4,2,6,3,6,2,2,3,0,0,0,0
|
||||
dd 5,4,1,2,6,0,1,3,0,2,3,1,4,2,6,0,0,0,0
|
||||
dd 5,1,5,3,0,2,1,5,5,2,5,3,2,5,5,5,1,16644,0
|
||||
dd 5,0,5,4,2,4,3,4,0,6,2,1,3,0,0,0,0,0,0
|
||||
dd 6,3,2,4,1,6,6,4,5,0,2,4,4,1,1,5,1,2184,0
|
||||
dd 3,1,3,4,3,2,3,2,0,0,0,3,2,5,3,0,0,0,0
|
||||
dd 5,2,2,4,5,6,6,0,1,4,3,1,6,2,5,0,0,0,0
|
||||
dd 1,4,0,6,2,4,1,6,0,4,6,5,2,3,5,0,0,0,0
|
||||
dd 5,5,3,5,1,5,4,0,4,4,4,2,6,2,5,0,0,0,0
|
||||
dd 6,3,2,2,1,2,6,6,3,1,3,1,4,4,0,0,0,0,0
|
||||
dd 0,0,0,2,4,1,6,5,0,0,6,4,6,6,5,3,1,7,0
|
||||
dd 5,3,2,1,4,1,5,6,1,0,1,1,5,2,6,5,1,4161,0
|
||||
dd 4,5,2,1,6,5,2,0,2,4,1,5,6,5,0,0,0,0,0
|
||||
dd 4,0,0,1,2,6,1,3,2,0,5,3,3,2,0,0,0,0,0
|
||||
dd 6,2,5,4,2,5,2,1,5,3,0,0,4,2,5,5,1,16644,0
|
||||
dd 4,6,2,0,5,1,1,1,0,3,1,5,3,0,4,5,2,8680,0
|
||||
dd 6,6,4,1,6,1,5,0,5,3,6,1,2,4,6,0,0,0,0
|
||||
dd 1,2,6,3,3,0,0,6,0,2,1,4,4,5,2,0,0,0,0
|
||||
dd 0,1,0,3,6,0,5,3,3,4,2,0,0,3,0,3,1,8456,0
|
||||
dd 3,2,2,2,0,5,4,1,3,5,4,1,4,0,6,2,1,14,0
|
||||
dd 1,2,6,1,6,4,6,6,3,6,0,0,3,0,6,7,1,16912,0
|
||||
dd 6,4,6,0,0,0,1,3,2,3,4,2,5,0,3,0,0,0,0
|
||||
dd 2,4,3,4,4,0,6,1,6,0,2,5,6,6,4,0,0,0,0
|
||||
dd 0,0,4,4,1,0,1,4,6,1,1,2,4,3,3,5,1,4228,0
|
||||
dd 4,6,6,4,2,0,0,2,5,0,1,6,4,5,3,0,0,0,0
|
||||
dd 3,0,4,3,4,4,3,3,1,3,1,0,4,6,1,0,0,0,0
|
||||
dd 5,6,0,2,6,4,3,5,0,3,4,6,4,5,1,0,0,0,0
|
||||
dd 1,1,6,2,5,0,6,1,6,5,2,3,6,4,2,0,0,0,0
|
||||
dd 0,2,6,0,0,3,1,4,2,0,1,5,5,5,3,5,1,14336,0
|
||||
dd 4,5,0,3,6,0,5,2,6,2,3,4,5,4,3,0,0,0,0
|
||||
dd 1,3,5,3,4,2,2,2,0,0,5,3,6,1,3,2,1,224,0
|
||||
dd 5,1,5,5,1,6,1,4,5,6,1,3,4,5,3,5,1,8456,0
|
||||
dd 0,2,1,3,2,4,3,5,2,0,3,4,4,0,1,0,0,0,0
|
||||
dd 3,2,4,6,5,4,3,2,0,0,4,4,2,1,0,0,0,0,0
|
||||
dd 2,4,3,0,6,1,2,3,3,4,6,1,3,1,2,3,1,4228,0
|
||||
dd 1,1,1,1,2,0,3,2,1,1,4,0,4,1,3,6,2,8463,0
|
||||
dd 3,3,6,2,2,4,3,0,6,6,4,2,0,4,5,0,0,0,0
|
||||
dd 3,3,3,4,2,5,6,0,0,3,1,1,5,3,3,3,1,7,0
|
||||
dd 2,5,6,4,1,3,1,5,6,5,1,1,6,6,4,0,0,0,0
|
||||
dd 3,6,4,3,5,6,0,0,5,4,6,2,0,5,3,0,0,0,0
|
||||
dd 2,2,6,3,4,0,0,6,0,2,2,1,5,4,6,0,0,0,0
|
||||
dd 4,2,0,3,6,3,6,6,5,1,6,6,0,4,3,0,0,0,0
|
||||
dd 4,1,2,2,2,4,3,1,2,4,1,0,4,5,2,4,2,16668,0
|
||||
dd 4,4,3,3,6,3,0,3,5,4,1,5,3,5,3,3,1,4228,0
|
||||
dd 4,1,3,6,4,1,3,4,5,4,5,5,5,2,0,5,1,7168,0
|
||||
dd 3,5,4,2,5,2,0,1,5,3,5,3,1,6,1,0,0,0,0
|
||||
dd 1,5,4,3,6,3,3,3,3,0,5,4,5,1,5,6,1,480,0
|
||||
dd 4,0,2,4,1,4,3,0,4,0,5,1,4,0,1,3,1,8322,0
|
||||
dd 6,3,2,3,5,5,6,4,0,0,0,2,6,0,1,7,1,4161,0
|
||||
dd 5,5,1,0,0,5,5,1,3,5,0,1,6,4,6,0,0,0,0
|
||||
dd 5,0,1,1,6,1,4,5,5,6,5,5,6,1,0,0,0,0,0
|
||||
dd 4,6,0,5,3,5,4,5,1,5,4,0,5,6,0,0,0,0,0
|
||||
dd 5,3,5,4,0,6,3,1,1,3,2,1,5,3,2,0,0,0,0
|
||||
dd 3,6,3,6,0,2,0,6,0,1,0,4,2,3,4,0,0,0,0
|
||||
dd 1,0,6,3,2,1,5,1,6,4,2,1,3,2,4,0,0,0,0
|
||||
dd 5,4,6,6,2,4,6,0,6,6,5,2,4,0,1,0,0,0,0
|
||||
dd 6,6,6,1,4,0,2,3,0,6,3,3,4,6,3,7,1,7,0
|
||||
dd 0,1,0,5,4,0,6,5,0,5,5,2,2,1,1,0,0,0,0
|
||||
dd 0,4,1,6,1,5,4,3,5,0,1,6,5,2,3,0,0,0,0
|
||||
dd 1,6,6,6,6,2,1,5,3,3,4,1,2,4,1,14,1,30,0
|
||||
dd 5,2,5,3,1,6,3,2,6,5,2,4,1,4,1,0,0,0,0
|
||||
dd 4,0,3,0,0,0,0,5,0,6,6,5,0,6,6,3,1,4368,0
|
||||
dd 1,2,3,1,5,0,2,6,3,5,6,4,2,0,0,0,0,0,0
|
||||
dd 6,6,6,6,5,3,1,3,2,4,1,5,5,6,3,14,1,15,0
|
||||
dd 3,0,0,1,6,1,0,2,2,2,5,5,6,4,2,2,1,896,0
|
||||
dd 4,3,0,2,3,4,1,5,6,1,0,6,3,3,6,0,0,0,0
|
||||
dd 5,0,0,4,6,1,3,0,0,1,5,0,4,6,6,0,0,0,0
|
||||
dd 5,4,2,2,3,6,3,4,4,0,4,0,3,6,2,0,0,0,0
|
||||
dd 6,4,5,3,5,2,5,0,5,6,1,3,5,4,1,5,1,4368,0
|
||||
dd 1,4,1,5,4,6,2,6,2,4,1,2,4,5,1,0,0,0,0
|
||||
dd 0,1,0,6,5,1,2,4,5,2,3,1,5,3,5,5,1,4368,0
|
||||
dd 2,4,1,6,1,3,1,6,1,3,0,2,0,4,5,0,0,0,0
|
||||
dd 5,6,0,5,5,4,0,0,1,3,5,6,6,1,3,0,0,0,0
|
||||
dd 1,2,3,3,4,5,4,5,0,5,0,2,6,6,6,7,1,28672,0
|
||||
dd 1,0,3,2,5,6,5,3,1,3,1,5,0,5,1,0,0,0,0
|
||||
dd 6,0,4,6,3,3,0,1,4,5,6,1,3,1,1,0,0,0,0
|
||||
dd 4,3,1,4,1,1,5,6,1,4,4,0,0,4,6,0,0,0,0
|
||||
dd 1,1,1,5,1,2,0,6,0,0,6,4,1,4,1,2,1,7,0
|
||||
dd 4,2,0,2,0,4,4,4,4,3,0,3,4,3,0,15,2,4577,0
|
||||
dd 6,5,3,5,3,1,2,3,4,2,1,2,3,2,1,3,1,4228,0
|
||||
dd 1,6,4,6,3,6,1,1,1,3,4,2,4,3,6,2,1,448,0
|
||||
dd 0,2,2,4,3,4,4,6,3,5,4,6,3,2,2,3,1,4368,0
|
||||
dd 5,3,3,5,0,4,1,1,3,0,1,0,5,4,4,0,0,0,0
|
||||
dd 3,2,5,6,6,5,6,0,5,6,5,6,6,2,0,0,0,0,0
|
||||
dd 6,1,2,6,4,2,3,3,2,5,6,6,4,6,4,0,0,0,0
|
||||
dd 0,4,0,2,0,0,4,5,1,1,4,5,0,1,5,0,0,0,0
|
||||
dd 1,3,5,0,2,4,2,3,0,6,2,2,6,6,5,0,0,0,0
|
||||
dd 0,1,4,3,2,2,1,1,1,0,4,5,5,0,6,2,1,448,0
|
||||
dd 2,2,3,5,4,4,5,4,5,3,2,1,2,2,1,0,0,0,0
|
||||
dd 2,1,3,2,4,5,6,3,2,6,0,2,2,3,5,0,0,0,0
|
||||
dd 3,0,0,5,0,2,0,6,4,4,0,1,1,3,4,3,1,1092,0
|
||||
dd 2,3,6,0,0,2,2,0,6,6,3,5,6,4,0,0,0,0,0
|
||||
dd 4,2,5,3,0,5,5,5,0,2,4,2,4,2,4,5,1,224,0
|
||||
dd 3,4,5,5,0,3,3,3,0,4,4,4,1,4,2,3,1,224,0
|
||||
dd 5,1,3,3,1,0,6,3,3,3,2,4,5,3,4,6,2,9096,0
|
||||
dd 1,2,0,2,0,5,1,5,6,6,1,6,4,0,2,0,0,0,0
|
||||
dd 4,0,6,4,4,6,1,5,0,6,1,2,3,6,0,0,0,0,0
|
||||
dd 3,6,1,2,4,5,6,6,1,5,0,0,3,3,4,0,0,0,0
|
||||
dd 1,4,2,4,4,5,2,2,6,2,5,2,2,2,1,4,2,14468,0
|
||||
dd 6,3,2,0,6,1,3,1,6,1,6,1,4,0,2,0,0,0,0
|
||||
dd 4,2,6,3,2,6,5,1,0,0,6,5,0,4,4,0,0,0,0
|
||||
dd 2,2,5,1,2,6,3,0,0,1,1,1,0,3,4,0,0,0,0
|
||||
dd 4,5,0,2,2,0,5,6,4,2,0,5,6,6,4,5,1,2114,0
|
||||
dd 3,5,4,6,1,6,0,2,6,0,3,0,0,5,0,0,0,0,0
|
||||
dd 3,0,6,0,1,2,3,2,1,0,5,2,4,6,3,0,0,0,0
|
||||
dd 6,3,1,4,6,4,0,4,6,0,2,4,6,0,3,12,2,6552,0
|
||||
dd 1,6,0,1,1,5,1,2,1,0,0,2,1,1,6,10,2,12633,0
|
||||
dd 1,0,4,5,6,0,3,0,2,6,3,3,4,0,0,3,1,8322,0
|
||||
dd 6,0,2,6,0,5,5,3,1,2,1,0,2,4,0,0,0,0,0
|
||||
dd 1,6,0,4,5,6,2,3,0,3,2,6,5,4,0,3,1,16644,0
|
||||
dd 0,2,4,5,3,3,2,0,5,3,5,3,0,2,6,0,0,0,0
|
||||
dd 6,6,2,2,1,3,3,5,5,2,4,4,3,4,2,0,0,0,0
|
||||
dd 6,2,2,5,2,2,6,2,0,1,4,3,6,5,3,7,1,4161,0
|
||||
dd 3,2,2,2,0,4,0,1,0,3,5,4,3,4,4,2,1,14,0
|
||||
dd 3,2,6,2,1,4,4,0,1,4,1,1,2,6,6,0,0,0,0
|
||||
dd 2,2,5,6,3,0,3,1,1,1,1,2,4,4,3,2,1,896,0
|
||||
dd 6,0,0,0,2,4,4,1,5,4,3,6,5,1,2,3,1,14,0
|
||||
dd 2,2,4,3,6,0,3,4,0,5,1,3,4,5,1,5,1,4228,0
|
||||
dd 6,0,1,2,0,2,2,0,5,2,2,6,5,6,5,0,0,0,0
|
||||
dd 6,2,6,5,5,6,6,3,4,4,6,4,5,0,6,14,2,1125,0
|
||||
dd 3,6,6,4,2,1,5,3,5,5,4,0,5,1,2,0,0,0,0
|
||||
dd 1,4,2,0,2,2,4,1,1,4,6,0,6,2,0,0,0,0,0
|
||||
dd 2,3,1,3,5,4,4,5,1,6,6,5,5,4,1,2,1,16644,0
|
||||
dd 6,6,5,6,6,6,2,6,2,6,0,3,1,4,0,0,0,0,0
|
||||
dd 1,4,4,5,2,2,0,6,3,6,6,2,5,2,3,0,0,0,0
|
||||
dd 1,1,4,6,5,6,0,6,3,2,4,5,6,2,6,0,0,0,0
|
||||
dd 4,1,2,2,2,6,1,3,1,2,6,5,4,3,4,2,1,28,0
|
||||
dd 0,2,5,4,3,6,5,5,4,3,5,1,1,3,4,5,1,1092,0
|
||||
dd 2,0,3,1,0,5,0,1,2,2,4,1,4,5,4,2,1,2184,0
|
||||
dd 2,5,3,0,4,2,2,1,2,6,1,2,4,1,1,0,0,0,0
|
||||
dd 6,1,4,6,5,5,0,6,3,5,0,5,3,6,4,0,0,0,0
|
||||
dd 1,1,2,5,5,5,1,3,1,2,3,5,1,2,2,2,1,4161,0
|
||||
dd 6,4,1,0,6,4,5,1,6,0,0,6,6,2,5,7,1,4368,0
|
||||
dd 0,2,6,1,2,5,4,5,5,3,4,2,4,2,5,0,0,0,0
|
||||
dd 5,3,0,6,3,0,2,4,6,4,2,4,6,4,3,0,0,0,0
|
||||
dd 4,0,6,6,0,1,5,5,5,1,5,6,6,6,0,12,2,14784,0
|
||||
dd 4,4,0,3,3,2,1,0,6,1,1,4,5,5,6,0,0,0,0
|
||||
dd 4,3,3,5,6,1,4,5,3,5,3,5,6,5,4,5,1,2184,0
|
||||
dd 5,3,2,2,1,0,3,5,5,5,5,4,0,6,1,5,1,896,0
|
||||
dd 6,3,5,3,4,0,0,0,1,3,3,2,4,3,6,3,1,224,0
|
||||
dd 0,6,1,1,4,1,4,3,2,1,4,3,4,3,4,0,0,0,0
|
||||
dd 3,4,6,6,6,1,2,3,1,2,5,0,2,1,5,7,1,28,0
|
||||
dd 2,2,1,5,5,2,2,3,3,1,0,6,6,6,5,7,1,14336,0
|
||||
dd 2,2,1,6,5,5,4,4,5,6,5,5,6,4,4,0,0,0,0
|
||||
dd 5,4,1,6,5,0,0,2,0,5,2,3,3,4,4,0,0,0,0
|
||||
dd 3,2,2,2,0,0,4,0,5,3,2,1,1,6,6,2,1,14,0
|
||||
dd 3,4,1,4,6,5,2,2,6,5,5,6,4,0,5,0,0,0,0
|
||||
dd 6,6,2,4,0,1,3,1,6,5,4,3,2,6,2,0,0,0,0
|
||||
dd 0,6,0,5,1,6,5,2,0,2,2,5,6,0,4,0,0,0,0
|
||||
dd 6,5,5,4,5,4,0,5,5,5,1,0,0,6,0,5,1,896,0
|
||||
dd 2,3,0,1,6,4,0,0,1,0,1,1,0,5,5,3,1,4228,0
|
||||
dd 5,5,3,6,3,5,5,3,0,5,6,4,0,0,1,0,0,0,0
|
||||
dd 4,2,2,0,5,2,3,6,3,3,4,3,3,2,1,0,0,0,0
|
||||
dd 0,0,0,0,2,0,4,1,1,2,2,3,4,4,6,6,1,15,0
|
||||
dd 6,1,0,3,0,2,3,6,1,5,5,0,2,2,3,0,0,0,0
|
||||
dd 3,6,5,3,6,4,6,6,5,4,6,1,6,1,4,0,0,0,0
|
||||
dd 0,2,3,2,5,5,1,2,1,5,4,3,5,0,1,0,0,0,0
|
||||
dd 4,0,2,5,3,6,3,3,6,4,3,3,0,4,5,0,0,0,0
|
||||
dd 2,1,3,1,0,5,3,4,2,0,1,3,3,5,5,0,0,0,0
|
||||
dd 1,2,1,6,2,5,0,2,2,0,0,5,5,1,3,0,0,0,0
|
||||
dd 2,3,2,0,3,3,3,2,1,0,6,5,4,2,6,0,0,0,0
|
||||
dd 3,0,1,6,6,5,4,0,4,2,0,4,2,6,4,0,0,0,0
|
||||
dd 4,6,5,6,6,0,1,2,1,1,2,1,1,2,0,0,0,0,0
|
||||
dd 2,2,4,6,5,4,6,5,6,5,3,1,2,6,6,7,1,8456,0
|
||||
dd 2,1,1,3,1,0,3,5,6,6,0,3,4,2,6,0,0,0,0
|
||||
dd 0,0,5,2,4,2,3,4,2,5,3,2,6,5,4,0,0,0,0
|
||||
dd 1,5,1,0,5,3,1,0,3,0,2,6,2,1,6,0,0,0,0
|
||||
dd 2,1,2,4,2,5,3,0,4,0,2,4,2,1,5,0,0,0,0
|
||||
dd 0,4,3,6,0,3,2,3,5,4,3,6,1,3,3,0,0,0,0
|
||||
dd 0,4,2,5,5,0,2,6,4,4,2,1,6,3,5,2,1,1092,0
|
||||
dd 3,0,1,1,3,1,0,5,0,1,5,1,3,5,0,0,0,0,0
|
||||
dd 6,0,0,1,6,1,5,1,6,3,4,0,0,6,5,0,0,0,0
|
||||
dd 6,0,6,6,1,0,0,5,6,6,2,0,4,6,0,10,2,10570,0
|
||||
dd 3,6,5,1,3,3,5,6,0,6,6,6,6,1,6,7,1,7168,0
|
||||
dd 3,5,2,4,3,0,3,1,5,0,0,3,2,5,3,0,0,0,0
|
||||
dd 0,4,2,4,2,3,3,1,4,4,0,1,6,2,3,0,0,0,0
|
||||
dd 6,6,6,4,4,6,3,0,4,6,2,5,4,6,2,12,2,4375,0
|
||||
dd 2,6,1,4,5,1,0,3,6,6,2,2,0,3,3,0,0,0,0
|
||||
dd 0,5,4,1,0,0,5,2,4,4,2,0,0,0,6,3,1,14336,0
|
||||
dd 2,1,6,3,2,4,6,2,6,5,1,0,6,6,3,0,0,0,0
|
||||
dd 2,2,3,0,1,2,0,6,6,3,3,0,2,4,2,0,0,0,0
|
||||
dd 0,3,1,3,0,3,4,4,4,4,6,3,6,4,1,10,1,960,0
|
||||
dd 1,6,2,4,4,4,2,2,1,5,1,3,2,0,1,2,1,4228,0
|
||||
dd 4,4,3,3,4,5,6,5,0,6,2,2,2,6,0,2,1,7168,0
|
||||
dd 2,4,4,3,6,2,4,4,5,3,6,4,3,5,2,5,1,2114,0
|
||||
dd 0,6,6,5,1,2,3,5,5,3,1,6,6,2,5,0,0,0,0
|
||||
dd 3,4,2,2,6,2,5,0,1,3,6,3,2,1,0,0,0,0,0
|
||||
dd 5,0,3,2,2,0,0,2,2,5,2,3,3,1,0,0,0,0,0
|
||||
dd 4,1,1,3,2,1,5,6,3,5,1,2,1,4,6,0,0,0,0
|
||||
dd 5,6,2,5,4,5,6,3,1,2,6,4,2,2,2,2,1,28672,0
|
||||
dd 5,6,4,1,6,1,3,0,6,5,3,3,3,1,1,3,1,7168,0
|
||||
dd 3,6,6,6,2,4,0,1,3,3,6,2,3,2,2,7,1,14,0
|
||||
dd 2,0,0,1,6,6,3,2,0,1,0,1,3,0,3,0,0,0,0
|
||||
dd 4,1,2,1,1,6,4,3,1,5,2,3,0,5,0,0,0,0,0
|
||||
dd 0,1,0,0,1,0,1,1,5,3,1,2,0,1,2,2,1,8322,0
|
||||
dd 3,6,4,5,5,6,4,6,0,3,6,5,4,6,6,7,1,8322,0
|
||||
dd 5,5,4,1,4,3,2,5,0,1,5,1,6,0,6,0,0,0,0
|
||||
dd 2,1,5,2,6,1,0,5,6,6,5,6,6,2,4,7,1,4368,0
|
||||
dd 0,1,3,3,3,5,1,2,2,1,0,2,0,1,5,3,1,28,0
|
||||
dd 2,4,2,3,3,0,6,3,0,2,6,5,6,6,3,0,0,0,0
|
||||
dd 5,5,6,6,1,0,0,4,0,6,4,1,2,2,5,0,0,0,0
|
||||
dd 4,4,4,0,6,3,1,6,1,1,4,2,3,5,6,5,1,7,0
|
||||
dd 4,6,6,4,1,4,6,0,3,1,0,6,2,3,2,7,1,2114,0
|
||||
dd 2,4,6,2,2,5,2,0,5,1,0,5,5,3,4,0,0,0,0
|
||||
dd 0,5,1,0,4,1,0,3,0,3,0,4,1,5,6,0,0,0,0
|
||||
dd 5,6,4,1,6,6,6,3,4,5,3,3,1,1,3,0,0,0,0
|
||||
dd 2,1,1,6,3,1,3,6,2,4,4,3,1,4,2,0,0,0,0
|
||||
dd 3,2,0,3,1,5,0,4,3,4,2,5,0,4,3,0,0,0,0
|
||||
dd 1,3,1,1,6,0,5,0,0,1,2,2,2,0,0,2,1,7168,0
|
||||
dd 4,2,5,5,2,4,2,6,6,2,5,4,6,2,5,0,0,0,0
|
||||
dd 2,2,6,1,2,3,5,6,6,3,6,0,6,1,2,7,1,4228,0
|
||||
dd 0,2,3,1,6,4,2,1,4,3,3,0,3,2,1,0,0,0,0
|
||||
dd 5,0,6,3,4,3,6,3,4,4,5,6,5,4,0,0,0,0,0
|
||||
dd 2,0,6,6,3,6,5,6,0,2,6,6,5,1,5,7,1,2184,0
|
||||
dd 0,4,3,4,4,5,4,1,0,3,6,0,0,5,6,0,0,0,0
|
||||
dd 5,6,1,2,3,4,1,3,1,4,2,2,0,5,0,0,0,0,0
|
||||
dd 6,1,4,1,3,5,6,6,4,6,2,5,4,3,1,0,0,0,0
|
||||
dd 2,1,3,0,5,2,3,1,2,4,2,3,2,2,6,2,1,1057,0
|
||||
dd 5,4,1,3,4,1,6,2,0,5,3,5,2,3,5,0,0,0,0
|
||||
dd 0,5,5,4,5,4,4,5,4,4,4,2,3,0,6,0,0,0,0
|
||||
dd 1,0,1,1,3,1,4,6,3,3,4,3,3,1,0,3,1,4368,0
|
||||
dd 3,5,5,6,1,5,1,5,6,5,2,0,0,4,1,0,0,0,0
|
||||
dd 4,3,4,5,2,2,2,1,4,2,5,0,5,2,3,0,0,0,0
|
||||
dd 1,1,6,4,6,1,1,3,2,2,3,0,4,2,0,0,0,0,0
|
||||
dd 1,1,1,6,2,1,1,3,3,3,5,6,5,0,2,5,2,903,0
|
||||
dd 5,0,0,4,6,6,3,5,6,3,1,6,6,2,1,7,1,4368,0
|
||||
dd 0,4,0,3,4,2,4,5,0,1,0,4,6,2,6,5,1,2114,0
|
||||
dd 5,6,2,6,6,2,6,3,5,2,2,5,3,2,3,0,0,0,0
|
||||
dd 5,0,5,0,3,3,1,1,4,4,5,0,6,5,5,0,0,0,0
|
||||
dd 4,4,1,3,0,4,6,2,4,3,3,1,1,4,3,0,0,0,0
|
||||
dd 5,2,3,3,3,3,5,4,3,4,4,3,3,5,4,6,2,4380,0
|
||||
dd 4,2,1,4,0,2,2,0,5,3,4,6,5,2,3,0,0,0,0
|
||||
dd 1,2,1,5,4,3,2,1,5,3,1,0,4,3,2,0,0,0,0
|
||||
dd 4,1,4,6,3,4,3,1,0,2,5,4,6,5,1,0,0,0,0
|
||||
dd 4,0,3,6,2,3,6,0,3,5,0,3,2,0,2,3,1,8322,0
|
||||
dd 6,1,2,3,4,2,4,4,1,1,0,2,2,2,4,2,1,14336,0
|
||||
dd 6,6,3,0,6,5,2,5,4,5,1,6,5,4,6,0,0,0,0
|
||||
dd 5,1,0,1,2,4,0,4,5,4,2,5,3,0,3,0,0,0,0
|
||||
dd 5,3,2,2,1,1,3,6,0,6,0,2,3,2,4,0,0,0,0
|
||||
dd 5,1,1,6,5,6,6,6,6,4,3,1,4,4,2,14,1,480,0
|
||||
dd 0,1,5,6,3,0,6,1,4,4,2,5,1,5,2,0,0,0,0
|
||||
dd 4,5,3,2,1,5,0,4,0,5,0,4,4,5,2,0,0,0,0
|
||||
dd 4,6,1,1,4,5,4,4,5,6,6,0,6,3,5,0,0,0,0
|
||||
dd 2,5,5,6,5,1,0,0,4,3,3,5,6,5,4,0,0,0,0
|
||||
dd 5,0,2,2,4,4,1,6,0,0,1,0,5,5,2,0,0,0,0
|
||||
dd 1,0,5,6,6,0,0,5,1,3,6,1,2,3,4,0,0,0,0
|
||||
dd 5,6,3,2,1,2,1,0,0,2,6,2,2,6,5,0,0,0,0
|
||||
dd 0,5,5,5,5,6,2,0,1,1,4,5,0,5,5,10,1,30,0
|
||||
dd 3,5,6,1,4,4,1,4,3,0,5,5,1,1,6,0,0,0,0
|
||||
dd 6,1,2,4,1,4,6,1,1,0,6,2,0,6,2,0,0,0,0
|
||||
dd 1,2,5,2,3,6,1,1,3,0,3,0,3,3,1,3,1,4368,0
|
||||
dd 0,6,5,6,3,6,0,5,2,0,0,2,2,5,4,0,0,0,0
|
||||
dd 2,5,4,4,3,0,6,5,6,0,0,2,6,6,0,0,0,0,0
|
||||
dd 6,4,1,0,1,1,1,3,2,6,2,1,2,2,6,0,0,0,0
|
||||
dd 5,0,1,5,6,4,0,6,4,1,0,3,2,3,0,0,0,0,0
|
||||
dd 2,6,4,6,1,0,0,3,5,5,5,5,4,5,5,0,0,0,0
|
||||
dd 0,2,6,4,3,5,1,6,3,0,3,1,5,5,6,0,0,0,0
|
||||
dd 5,0,1,2,1,3,3,4,6,6,5,2,6,6,2,0,0,0,0
|
||||
dd 1,3,3,5,4,3,4,5,4,2,0,3,6,4,2,0,0,0,0
|
||||
dd 5,6,6,6,5,2,0,5,6,5,5,2,0,1,3,7,1,14,0
|
||||
dd 0,0,5,6,5,6,5,4,0,2,3,1,0,6,1,0,0,0,0
|
||||
dd 6,3,3,2,3,0,5,2,0,1,2,4,6,3,1,0,0,0,0
|
||||
dd 6,3,2,4,4,4,4,2,1,2,1,1,3,6,1,0,0,0,0
|
||||
dd 4,4,1,5,3,1,4,6,4,2,2,2,4,2,1,5,1,4161,0
|
||||
dd 6,2,0,5,6,2,5,6,4,2,5,0,0,4,2,0,0,0,0
|
||||
dd 6,5,3,1,5,2,3,4,5,5,1,0,0,1,6,0,0,0,0
|
||||
dd 4,3,6,3,5,3,4,5,2,4,0,5,1,0,1,0,0,0,0
|
||||
dd 1,1,4,6,3,6,5,2,0,0,0,5,0,6,5,0,0,0,0
|
||||
dd 0,6,0,4,6,6,5,5,0,4,1,6,3,4,2,0,0,0,0
|
||||
dd 1,6,0,1,5,5,3,6,5,3,0,1,6,4,3,0,0,0,0
|
||||
dd 4,1,5,6,5,4,4,5,6,2,3,1,6,3,6,0,0,0,0
|
||||
dd 1,3,1,0,6,3,0,4,5,4,0,3,6,6,3,0,0,0,0
|
||||
dd 0,6,3,5,3,2,6,2,1,2,5,2,3,4,4,0,0,0,0
|
||||
.code
|
||||
273
tools/tests/clover_test.inc
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
include tools\tests\clover_fixtures.inc
|
||||
.data
|
||||
clpTestStage3D dd 0
|
||||
clpTestReady db "build\actions\clover-ready.bmp",0
|
||||
clpTestSpin db "build\actions\clover-spin.bmp",0
|
||||
clpTestStopped db "build\actions\clover-stopped.bmp",0
|
||||
clpTestWin db "build\actions\clover-win.bmp",0
|
||||
clpTestNext db "build\actions\clover-next.bmp",0
|
||||
clpTestPay db "build\actions\clover-paytable.bmp",0
|
||||
.code
|
||||
RunCloverTest3D PROC uses ebx esi edi
|
||||
local oldBank:DWORD,oldMode:DWORD,oldSeed:DWORD,iterations:DWORD
|
||||
local fixture:DWORD,expected:DWORD,rngSnapshot:DWORD,previous:DWORD,ticks:DWORD
|
||||
mov eax,bankroll
|
||||
mov oldBank,eax
|
||||
mov eax,engineMode
|
||||
mov oldMode,eax
|
||||
mov eax,rngSeed3D
|
||||
mov oldSeed,eax
|
||||
mov clpTestStage3D,1
|
||||
mov engineMode,MODE_WALK
|
||||
mov interactTargetId,INTERACT_SLOTS_CLOVER
|
||||
call Trigger3DInteraction
|
||||
cmp engineMode,MODE_CLOVER
|
||||
jne clp_test_fail
|
||||
call TableBusy3D
|
||||
test eax,eax
|
||||
jnz clp_test_fail
|
||||
call RenderNativeClover3D
|
||||
invoke WriteActionSnapshot3D,OFFSET clpTestReady
|
||||
test eax,eax
|
||||
jz clp_test_fail
|
||||
mov clpTestStage3D,2
|
||||
lea ebx,clpFixtures3D
|
||||
mov iterations,clpFixtureCount3D
|
||||
clp_test_fixture:
|
||||
mov fixture,ebx
|
||||
mov esi,ebx
|
||||
lea edi,clpGrid3D
|
||||
mov ecx,15
|
||||
rep movsd
|
||||
call CloverEvaluate3D
|
||||
mov ebx,fixture
|
||||
mov eax,[ebx+60]
|
||||
cmp clpTotal3D,eax
|
||||
jne clp_test_fail
|
||||
mov eax,[ebx+64]
|
||||
cmp clpCount3D,eax
|
||||
jne clp_test_fail
|
||||
mov eax,[ebx+68]
|
||||
cmp clpWinMask3D,eax
|
||||
jne clp_test_fail
|
||||
mov eax,[ebx+72]
|
||||
cmp clpJackpot3D,eax
|
||||
jne clp_test_fail
|
||||
xor esi,esi
|
||||
xor edi,edi
|
||||
clp_test_combo_sum:
|
||||
cmp esi,clpCount3D
|
||||
jae @F
|
||||
add edi,clpMults3D[esi*4]
|
||||
mov eax,clpMasks3D[esi*4]
|
||||
test eax,eax
|
||||
jz clp_test_fail
|
||||
and eax,clpWinMask3D
|
||||
cmp eax,clpMasks3D[esi*4]
|
||||
jne clp_test_fail
|
||||
inc esi
|
||||
jmp clp_test_combo_sum
|
||||
@@:
|
||||
cmp edi,clpTotal3D
|
||||
jne clp_test_fail
|
||||
add ebx,76
|
||||
dec iterations
|
||||
jnz clp_test_fixture
|
||||
mov clpGrid3D,7
|
||||
call CloverEvaluate3D
|
||||
cmp clpTotal3D,0
|
||||
jne clp_test_fail
|
||||
cmp clpCount3D,0
|
||||
jne clp_test_fail
|
||||
mov clpGrid3D,0
|
||||
mov clpTestStage3D,3
|
||||
mov clpBet3D,50
|
||||
mov bankroll,49
|
||||
mov clpState3D,SLOT_READY
|
||||
mov eax,rngSeed3D
|
||||
mov rngSnapshot,eax
|
||||
call StartNativeClover3D
|
||||
cmp bankroll,49
|
||||
jne clp_test_fail
|
||||
mov eax,rngSnapshot
|
||||
cmp rngSeed3D,eax
|
||||
jne clp_test_fail
|
||||
mov iterations,500
|
||||
clp_test_round:
|
||||
call ClearKeys3D
|
||||
mov engineMode,MODE_CLOVER
|
||||
mov clpState3D,SLOT_READY
|
||||
mov clpBet3D,100
|
||||
mov bankroll,100000
|
||||
call StartNativeClover3D
|
||||
cmp bankroll,99900
|
||||
jne clp_test_fail
|
||||
cmp clpState3D,SLOT_SPIN
|
||||
jne clp_test_fail
|
||||
mov eax,rngSeed3D
|
||||
mov rngSnapshot,eax
|
||||
call CloverEvaluate3D
|
||||
mov eax,clpTotal3D
|
||||
imul eax,100
|
||||
add eax,99900
|
||||
mov expected,eax
|
||||
mov clpCount3D,0
|
||||
mov clpTotal3D,0
|
||||
call StartNativeClover3D
|
||||
cmp bankroll,99900
|
||||
jne clp_test_fail
|
||||
mov eax,iterations
|
||||
and eax,3
|
||||
mov eax,slotsTestRates[eax*4]
|
||||
mov deltaTime3D,eax
|
||||
mov ticks,0
|
||||
; Queue exit for half the rounds, without cancelling or repaying.
|
||||
test iterations,1
|
||||
jz @F
|
||||
call CardTableEscape3D
|
||||
@@:
|
||||
clp_test_round_tick:
|
||||
mov pressedKeys3D[57h],1
|
||||
mov pressedKeys3D[20h],1
|
||||
call HandleNativeClover3D
|
||||
call ClearKeys3D
|
||||
cmp clpBet3D,100
|
||||
jne clp_test_fail
|
||||
mov eax,rngSnapshot
|
||||
cmp rngSeed3D,eax
|
||||
jne clp_test_fail
|
||||
inc ticks
|
||||
cmp ticks,220
|
||||
ja clp_test_fail
|
||||
cmp clpState3D,SLOT_SPIN
|
||||
je clp_test_round_tick
|
||||
mov eax,expected
|
||||
cmp bankroll,eax
|
||||
jne clp_test_fail
|
||||
call SettleNativeClover3D
|
||||
mov eax,expected
|
||||
cmp bankroll,eax
|
||||
jne clp_test_fail
|
||||
test iterations,1
|
||||
jz @F
|
||||
cmp engineMode,MODE_WALK
|
||||
jne clp_test_fail
|
||||
@@:
|
||||
xor esi,esi
|
||||
clp_test_final_column:
|
||||
mov ebx,esi
|
||||
shl ebx,8
|
||||
mov ecx,clpSteps3D[esi*4]
|
||||
lea ebx,clpTape3D[ebx+ecx*4]
|
||||
xor edi,edi
|
||||
clp_test_final_row:
|
||||
mov ecx,edi
|
||||
imul ecx,5
|
||||
add ecx,esi
|
||||
mov eax,[ebx+edi*4]
|
||||
cmp eax,clpGrid3D[ecx*4]
|
||||
jne clp_test_fail
|
||||
inc edi
|
||||
cmp edi,3
|
||||
jb clp_test_final_row
|
||||
inc esi
|
||||
cmp esi,5
|
||||
jb clp_test_final_column
|
||||
dec iterations
|
||||
jnz clp_test_round
|
||||
mov clpTestStage3D,4
|
||||
mov clpState3D,SLOT_SPIN
|
||||
xor esi,esi
|
||||
clp_test_monotonic_column:
|
||||
mov clpTimer3D,0
|
||||
mov previous,0
|
||||
clp_test_monotonic_tick:
|
||||
invoke CloverReelPosition3D,esi
|
||||
cmp eax,previous
|
||||
jb clp_test_fail
|
||||
mov previous,eax
|
||||
inc clpTimer3D
|
||||
cmp clpTimer3D,3400
|
||||
jbe clp_test_monotonic_tick
|
||||
mov eax,clpSteps3D[esi*4]
|
||||
imul eax,CLP_CELL
|
||||
cmp eax,previous
|
||||
jne clp_test_fail
|
||||
inc esi
|
||||
cmp esi,5
|
||||
jb clp_test_monotonic_column
|
||||
mov clpTestStage3D,5
|
||||
mov clpState3D,SLOT_READY
|
||||
mov bankroll,100000
|
||||
call StartNativeClover3D
|
||||
mov clpTimer3D,900
|
||||
mov eax,rngSeed3D
|
||||
mov rngSnapshot,eax
|
||||
call RenderNativeClover3D
|
||||
mov eax,rngSnapshot
|
||||
cmp rngSeed3D,eax
|
||||
jne clp_test_fail
|
||||
cmp bankroll,99900
|
||||
jne clp_test_fail
|
||||
invoke WriteActionSnapshot3D,OFFSET clpTestSpin
|
||||
mov clpTimer3D,2200
|
||||
call RenderNativeClover3D
|
||||
invoke WriteActionSnapshot3D,OFFSET clpTestStopped
|
||||
; Force an all-seven jackpot and inspect distinct paid masks.
|
||||
lea edi,clpGrid3D
|
||||
mov eax,6
|
||||
mov ecx,15
|
||||
rep stosd
|
||||
mov clpLeave3D,0
|
||||
mov engineMode,MODE_CLOVER
|
||||
call SettleNativeClover3D
|
||||
cmp clpJackpot3D,1
|
||||
jne clp_test_fail
|
||||
cmp clpCount3D,2
|
||||
jb clp_test_fail
|
||||
call RenderNativeClover3D
|
||||
invoke WriteActionSnapshot3D,OFFSET clpTestWin
|
||||
mov pressedKeys3D[27h],1
|
||||
call HandleNativeClover3D
|
||||
cmp clpSelected3D,1
|
||||
jne clp_test_fail
|
||||
call RenderNativeClover3D
|
||||
invoke WriteActionSnapshot3D,OFFSET clpTestNext
|
||||
mov clpPaytable3D,1
|
||||
call RenderNativeClover3D
|
||||
invoke WriteActionSnapshot3D,OFFSET clpTestPay
|
||||
call CardTableEscape3D
|
||||
cmp engineMode,MODE_CLOVER
|
||||
jne clp_test_fail
|
||||
cmp clpPaytable3D,0
|
||||
jne clp_test_fail
|
||||
call CardTableEscape3D
|
||||
cmp engineMode,MODE_WALK
|
||||
jne clp_test_fail
|
||||
mov clpTestStage3D,6
|
||||
mov clpState3D,SLOT_SPIN
|
||||
mov clpStake3D,10000
|
||||
mov bankroll,999999999
|
||||
call SettleNativeClover3D
|
||||
cmp bankroll,1000000000
|
||||
jne clp_test_fail
|
||||
cmp clpGross3D,1
|
||||
jne clp_test_fail
|
||||
call SettleNativeClover3D
|
||||
cmp bankroll,1000000000
|
||||
jne clp_test_fail
|
||||
mov eax,oldBank
|
||||
mov bankroll,eax
|
||||
mov eax,oldMode
|
||||
mov engineMode,eax
|
||||
mov eax,oldSeed
|
||||
mov rngSeed3D,eax
|
||||
call ClearKeys3D
|
||||
call FreeNativeClover3D
|
||||
xor eax,eax
|
||||
ret
|
||||
clp_test_fail:
|
||||
mov eax,clpTestStage3D
|
||||
add eax,860
|
||||
ret
|
||||
RunCloverTest3D ENDP
|
||||
|
|
@ -90,6 +90,8 @@ include tools\tests\world_regression.inc
|
|||
include tools\tests\hall_furniture_test.inc
|
||||
include tools\tests\wheel_scene_test.inc
|
||||
|
||||
include tools\tests\npc_life_test.inc
|
||||
|
||||
RunHallTest3D PROC uses ebx esi edi
|
||||
local oldBank:DWORD,oldSeed:DWORD,endX:DWORD,endV:DWORD
|
||||
mov eax, bankroll
|
||||
|
|
@ -122,19 +124,12 @@ RunHallTest3D PROC uses ebx esi edi
|
|||
call TestHallSurface3D
|
||||
cmp eax, 1
|
||||
jne hall_test_fail
|
||||
; Sample the entire walking route; every accepted position must stay navigable.
|
||||
; Visible people use the same personality positions as the new simulation.
|
||||
mov patronClock3D, 0
|
||||
mov deltaTime3D, 50
|
||||
mov ebx, 400
|
||||
hall_test_patron_route:
|
||||
call UpdatePatrons3D
|
||||
cmp ebx, 201
|
||||
jne @F
|
||||
cmp hallGuests3D.posX,22*FP_1
|
||||
jne hall_test_fail
|
||||
cmp hallGuests3D.posY,20*FP_1
|
||||
jne hall_test_fail
|
||||
@@:
|
||||
invoke CanWalk3D,hallGuests3D.posX,hallGuests3D.posY
|
||||
cmp eax, 1
|
||||
jne hall_test_fail
|
||||
|
|
@ -145,10 +140,6 @@ hall_test_patron_route:
|
|||
jnz hall_test_patron_route
|
||||
cmp patronClock3D, 0
|
||||
jne hall_test_fail
|
||||
cmp hallGuests3D.posX,18*FP_1
|
||||
jne hall_test_fail
|
||||
cmp hallGuests3D.posY,18*FP_1
|
||||
jne hall_test_fail
|
||||
invoke CanWalk3D,4*FP_1,27*FP_1
|
||||
test eax, eax
|
||||
jnz hall_test_fail
|
||||
|
|
@ -297,7 +288,7 @@ hall_test_two_balls:
|
|||
jb hall_test_two_balls
|
||||
mov poolX3D, 100*FP_1
|
||||
mov poolY3D, 115*FP_1
|
||||
mov poolX3D[4], 105*FP_1+FP_1*4/5
|
||||
mov poolX3D[4], 102*FP_1+FP_1*4/5
|
||||
mov poolY3D[4], 115*FP_1
|
||||
mov poolVX3D, FP_1
|
||||
invoke PoolCollide3D,0,1
|
||||
|
|
@ -324,7 +315,7 @@ hall_test_fast_contact:
|
|||
cmp poolVX3D[4], 0
|
||||
jle hall_test_fail
|
||||
mov poolActive3D[4], 0
|
||||
mov poolX3D, 33*FP_1
|
||||
mov poolX3D, 31*FP_1
|
||||
mov poolVX3D, -30000
|
||||
call PoolStep3D
|
||||
cmp poolVX3D, 0
|
||||
|
|
@ -334,7 +325,7 @@ hall_test_fast_contact:
|
|||
mov hallTestStage3D, 75
|
||||
mov poolActive3D[4], 0
|
||||
mov poolX3D, 160*FP_1
|
||||
mov poolY3D, 52*FP_1
|
||||
mov poolY3D, 51*FP_1+FP_1/2
|
||||
invoke PoolPocketBall3D,0
|
||||
cmp poolActive3D, 0
|
||||
jne hall_test_fail
|
||||
|
|
@ -342,8 +333,8 @@ hall_test_fast_contact:
|
|||
jne hall_test_fail
|
||||
; Near a middle pocket, the jaw must rebound an off-center approach.
|
||||
mov poolActive3D, 1
|
||||
mov poolX3D, 145*FP_1
|
||||
mov poolY3D, 64*FP_1
|
||||
mov poolX3D, 157*FP_1
|
||||
mov poolY3D, 52*FP_1
|
||||
mov poolVX3D, 0
|
||||
mov poolVY3D, -20000
|
||||
invoke PoolJawContact3D,0
|
||||
|
|
@ -397,16 +388,15 @@ hall_test_friction:
|
|||
mov poolRail3D, 1
|
||||
mov poolActive3D[8*4], 0
|
||||
mov poolPotted3D, 100h
|
||||
mov pyrScore3D,7
|
||||
call PoolFinishShot3D
|
||||
cmp poolState3D, POOL_RESULT
|
||||
jne hall_test_fail
|
||||
cmp poolWinner3D, 1
|
||||
cmp poolWinner3D, 0
|
||||
jne hall_test_fail
|
||||
call InitPool3D
|
||||
mov poolGroups3D, 1
|
||||
mov poolAtStart3D, 0
|
||||
mov poolBreak3D, 0
|
||||
mov poolFirst3D, 8
|
||||
mov poolFirst3D, -1
|
||||
mov poolRail3D, 1
|
||||
mov poolActive3D[8*4], 0
|
||||
mov poolPotted3D, 100h
|
||||
|
|
@ -414,7 +404,12 @@ hall_test_friction:
|
|||
mov poolCalledPocket3D, 0
|
||||
mov poolPocket3D[8*4], 0
|
||||
call PoolFinishShot3D
|
||||
cmp poolWinner3D, 0
|
||||
cmp poolState3D,POOL_PENALTY
|
||||
jne hall_test_fail
|
||||
cmp poolActive3D[8*4],1
|
||||
jne hall_test_fail
|
||||
invoke PyramidPenalty3D,1
|
||||
cmp pyrScore3D[4],1
|
||||
jne hall_test_fail
|
||||
call InitPool3D
|
||||
call RenderPool3D
|
||||
|
|
@ -431,6 +426,12 @@ hall_test_friction:
|
|||
call RunWorldRegression3D
|
||||
test eax, eax
|
||||
jz hall_test_fail
|
||||
call RunPyramidTest3D
|
||||
test eax,eax
|
||||
jnz hall_test_fail
|
||||
call RunNpcLifeTest3D
|
||||
test eax,eax
|
||||
jnz hall_test_fail
|
||||
mov eax, oldSeed
|
||||
cmp eax, rngSeed3D
|
||||
jne hall_test_fail
|
||||
|
|
|
|||
20
tools/tests/npc_life_probe.asm
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
.386
|
||||
.model flat,stdcall
|
||||
option casemap:none
|
||||
include F:\MASM32\masm32\include\windows.inc
|
||||
include F:\MASM32\masm32\include\kernel32.inc
|
||||
InitPaths3D PROTO
|
||||
LoadTextures3D PROTO
|
||||
InitializeCasinoSprites3D PROTO
|
||||
LoadHallAssets3D PROTO
|
||||
RunNpcLifeTest3D PROTO
|
||||
.code
|
||||
RunNpcLifeProbe PROC
|
||||
call InitPaths3D
|
||||
call LoadTextures3D
|
||||
call InitializeCasinoSprites3D
|
||||
call LoadHallAssets3D
|
||||
call RunNpcLifeTest3D
|
||||
invoke ExitProcess,eax
|
||||
RunNpcLifeProbe ENDP
|
||||
END
|
||||
227
tools/tests/npc_life_test.inc
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
.data
|
||||
npcTestBase1 db "build\arrival\fixtures\npc-one.dat",0
|
||||
npcTestBase2 db "build\arrival\fixtures\npc-two.dat",0
|
||||
npcTestJournal1 db "build\arrival\fixtures\npc-one.dat.npc",0
|
||||
npcTestJournal2 db "build\arrival\fixtures\npc-two.dat.npc",0
|
||||
npcTestOpenShot db "build\actions\npc-dialog-open.bmp",0
|
||||
npcTestReadyShot db "build\actions\npc-dialog-ready.bmp",0
|
||||
npcTestDoneShot db "build\actions\npc-dialog-done.bmp",0
|
||||
.code
|
||||
RunNpcLifeTest3D PROC uses ebx esi edi
|
||||
local oldBank:DWORD,steps:DWORD,identity:DWORD,firstX:DWORD,firstY:DWORD,claimBank:DWORD
|
||||
mov eax,bankroll
|
||||
mov oldBank,eax
|
||||
mov hallTestStage3D,7901
|
||||
call InitHall3D
|
||||
xor esi,esi
|
||||
npc_test_destinations:
|
||||
invoke NpcPlanPath3D,0,esi
|
||||
cmp eax,1
|
||||
jne npc_test_fail
|
||||
inc esi
|
||||
cmp esi,NPC_DEST_COUNT
|
||||
jb npc_test_destinations
|
||||
mov esi,20
|
||||
npc_test_rate:
|
||||
call InitNpcLife3D
|
||||
mov playerX,30*FP_1+FP_HALF
|
||||
mov playerY,30*FP_1+FP_HALF
|
||||
mov edi,1
|
||||
npc_test_rate_clear_crowd:
|
||||
imul ebx,edi,SIZEOF NpcLife3D
|
||||
mov npcLife3D[ebx].state,NPC_AWAY
|
||||
inc edi
|
||||
cmp edi,NPC_LIFE_COUNT
|
||||
jb npc_test_rate_clear_crowd
|
||||
invoke NpcPlanPath3D,0,5
|
||||
cmp eax,1
|
||||
jne npc_test_fail
|
||||
mov eax,2000
|
||||
xor edx,edx
|
||||
div esi
|
||||
mov steps,eax
|
||||
npc_test_rate_step:
|
||||
invoke NpcMove3D,0,esi
|
||||
dec steps
|
||||
jnz npc_test_rate_step
|
||||
mov eax,casinoNpcs3D.posX
|
||||
mov edx,casinoNpcs3D.posY
|
||||
cmp esi,20
|
||||
jne npc_test_rate_compare
|
||||
mov firstX,eax
|
||||
mov firstY,edx
|
||||
mov esi,50
|
||||
jmp npc_test_rate
|
||||
npc_test_rate_compare:
|
||||
cmp eax,firstX
|
||||
jne npc_test_fail
|
||||
cmp edx,firstY
|
||||
jne npc_test_fail
|
||||
cmp esi,100
|
||||
je npc_test_routes
|
||||
mov esi,100
|
||||
jmp npc_test_rate
|
||||
npc_test_routes:
|
||||
mov hallTestStage3D,7902
|
||||
call InitNpcLife3D
|
||||
mov deltaTime3D,50
|
||||
mov steps,2400
|
||||
npc_test_simulate:
|
||||
call UpdateNpcLife3D
|
||||
xor esi,esi
|
||||
npc_test_person_bounds:
|
||||
imul ebx,esi,SIZEOF NpcMindEntity
|
||||
invoke CanWalk3D,casinoNpcs3D[ebx].posX,casinoNpcs3D[ebx].posY
|
||||
cmp eax,1
|
||||
jne npc_test_fail
|
||||
imul edi,esi,SIZEOF NpcLife3D
|
||||
cmp npcLife3D[edi].state,NPC_AWAY
|
||||
ja npc_test_fail
|
||||
cmp npcLife3D[edi].identity,NPC_IDENTITY_COUNT
|
||||
jae npc_test_fail
|
||||
cmp npcLife3D[edi].pathCount,NPC_PATH_CAP
|
||||
ja npc_test_fail
|
||||
inc esi
|
||||
cmp esi,NPC_LIFE_COUNT
|
||||
jb npc_test_person_bounds
|
||||
dec steps
|
||||
jnz npc_test_simulate
|
||||
cmp npcLifeClock3D,120000
|
||||
jne npc_test_fail
|
||||
mov hallTestStage3D,7903
|
||||
invoke DeleteFileA,OFFSET npcTestJournal1
|
||||
invoke DeleteFileA,OFFSET npcTestJournal2
|
||||
mov npcJournalBasePtr3D,OFFSET npcTestBase1
|
||||
mov npcDateOverride3D,20261012
|
||||
mov npcJournalLoaded3D,0
|
||||
call NpcEnsureJournal3D
|
||||
cmp eax,1
|
||||
jne npc_test_fail
|
||||
xor esi,esi
|
||||
npc_test_find_any:
|
||||
invoke NpcContractType3D,esi
|
||||
test eax,eax
|
||||
jz npc_test_accept
|
||||
inc esi
|
||||
cmp esi,NPC_IDENTITY_COUNT
|
||||
jb npc_test_find_any
|
||||
jmp npc_test_fail
|
||||
npc_test_accept:
|
||||
mov identity,esi
|
||||
invoke NpcRecordRound3D,0,1
|
||||
cmp npcProgress3D[esi*4],0
|
||||
jne npc_test_fail
|
||||
invoke NpcAcceptContract3D,esi
|
||||
cmp eax,1
|
||||
jne npc_test_fail
|
||||
invoke NpcClaimContract3D,esi
|
||||
test eax,eax
|
||||
jnz npc_test_fail
|
||||
; A real legacy graphical settlement contributes once, including repeat protection.
|
||||
mov skulls3d_state,3
|
||||
mov skulls3d_choice,0
|
||||
mov skulls3d_ballPos,0
|
||||
mov skulls3d_bet,50
|
||||
call FinalizeSkullsGuess
|
||||
cmp npcProgress3D[esi*4],1
|
||||
jne npc_test_fail
|
||||
mov eax,bankroll
|
||||
mov claimBank,eax
|
||||
call FinalizeSkullsGuess
|
||||
mov eax,claimBank
|
||||
cmp bankroll,eax
|
||||
jne npc_test_fail
|
||||
cmp npcProgress3D[esi*4],1
|
||||
jne npc_test_fail
|
||||
invoke NpcRecordRound3D,1,1
|
||||
invoke NpcRecordRound3D,2,0
|
||||
invoke NpcRecordRound3D,3,1
|
||||
cmp npcProgress3D[esi*4],3
|
||||
jne npc_test_fail
|
||||
invoke NpcClaimContract3D,esi
|
||||
cmp eax,1
|
||||
jne npc_test_fail
|
||||
mov eax,claimBank
|
||||
add eax,150
|
||||
cmp bankroll,eax
|
||||
jne npc_test_fail
|
||||
mov npcJournalLoaded3D,0
|
||||
call NpcEnsureJournal3D
|
||||
invoke NpcClaimContract3D,identity
|
||||
test eax,eax
|
||||
jnz npc_test_fail
|
||||
mov hallTestStage3D,7904
|
||||
mov npcJournalBasePtr3D,OFFSET npcTestBase2
|
||||
call NpcEnsureJournal3D
|
||||
cmp npcAccepted3D,0
|
||||
jne npc_test_fail
|
||||
cmp npcClaimed3D,0
|
||||
jne npc_test_fail
|
||||
call InitNpcLife3D
|
||||
mov playerX,16*FP_1+FP_HALF
|
||||
mov playerY,18*FP_1+FP_HALF
|
||||
mov playerAngle,384
|
||||
call UpdateCamera3D
|
||||
mov interactTargetId,0
|
||||
call CheckNpcInteractions3D
|
||||
cmp interactTargetId,INTERACT_NPC
|
||||
jne npc_test_fail
|
||||
cmp npcSelected3D,0
|
||||
jne npc_test_fail
|
||||
call TriggerHallInteraction3D
|
||||
cmp engineMode,MODE_NPC_DIALOG
|
||||
jne npc_test_fail
|
||||
call RenderNpcDialog3D
|
||||
invoke WriteActionSnapshot3D,OFFSET npcTestOpenShot
|
||||
mov mouseClick3D,1
|
||||
mov mouseX3D,60
|
||||
mov mouseY3D,175
|
||||
call HandleNpcDialog3D
|
||||
bt npcAccepted3D,0
|
||||
jnc npc_test_fail
|
||||
mov ebx,3
|
||||
npc_test_finish_dialog:
|
||||
xor esi,esi
|
||||
npc_test_finish_games:
|
||||
invoke NpcRecordRound3D,esi,1
|
||||
inc esi
|
||||
cmp esi,6
|
||||
jb npc_test_finish_games
|
||||
dec ebx
|
||||
jnz npc_test_finish_dialog
|
||||
call RenderNpcDialog3D
|
||||
invoke WriteActionSnapshot3D,OFFSET npcTestReadyShot
|
||||
mov mouseClick3D,1
|
||||
mov mouseX3D,145
|
||||
mov mouseY3D,175
|
||||
call HandleNpcDialog3D
|
||||
bt npcClaimed3D,0
|
||||
jnc npc_test_fail
|
||||
call RenderNpcDialog3D
|
||||
invoke WriteActionSnapshot3D,OFFSET npcTestDoneShot
|
||||
call CardTableEscape3D
|
||||
cmp eax,1
|
||||
jne npc_test_fail
|
||||
cmp engineMode,MODE_WALK
|
||||
jne npc_test_fail
|
||||
mov npcDateOverride3D,20261013
|
||||
call NpcEnsureJournal3D
|
||||
cmp npcAccepted3D,0
|
||||
jne npc_test_fail
|
||||
cmp npcClaimed3D,0
|
||||
jne npc_test_fail
|
||||
mov npcAccepted3D,0
|
||||
mov npcClaimed3D,0
|
||||
mov npcJournalLoaded3D,0
|
||||
mov npcDateOverride3D,0
|
||||
mov npcJournalBasePtr3D,OFFSET npcJournalTestBase3D
|
||||
mov deltaTime3D,16
|
||||
mov eax,oldBank
|
||||
mov bankroll,eax
|
||||
call ClearKeys3D
|
||||
xor eax,eax
|
||||
ret
|
||||
npc_test_fail:
|
||||
mov eax,hallTestStage3D
|
||||
ret
|
||||
RunNpcLifeTest3D ENDP
|
||||