Implement native slots, coin toss, European roulette and hall furniture
Add native assembly scenes and assets for Slots (777), Coin flip, and European Roulette; add 3D hall furniture packs and prompts; improve Russian UI strings in CP1251; update launcher hash and rebuild shipping binaries.
2
.gitignore
vendored
|
|
@ -14,9 +14,11 @@ __pycache__/
|
|||
/build/actions/
|
||||
/build/arrival/
|
||||
/build/buckshot/
|
||||
/build/coin/
|
||||
/build/hall/
|
||||
/build/startup/
|
||||
/build/tables/
|
||||
/build/wheel/
|
||||
/build/*.res
|
||||
/build/payload_*.zip
|
||||
/build/PokerGameSetup_base.exe
|
||||
|
|
|
|||
BIN
assets/animations/coin/faces-v1.bin
Normal file
BIN
assets/animations/coin/hands-v1.bin
Normal file
BIN
assets/animations/coin/hands-v2.bin
Normal file
20
assets/animations/coin/manifest-v1.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"table": [
|
||||
640,
|
||||
480,
|
||||
1
|
||||
],
|
||||
"faces": [
|
||||
128,
|
||||
128,
|
||||
2
|
||||
],
|
||||
"hands": [
|
||||
224,
|
||||
224,
|
||||
16
|
||||
],
|
||||
"hand_anchor": "held coin (88,24); empty hand shared grid cell",
|
||||
"held_frames": 5,
|
||||
"alpha": "opaque table, binary cutouts"
|
||||
}
|
||||
BIN
assets/animations/coin/table-v1.bin
Normal file
BIN
assets/animations/hall/backroom-table-v5.bin
Normal file
BIN
assets/animations/hall/card-table-v5.bin
Normal file
BIN
assets/animations/hall/lamp-table-v5.bin
Normal file
BIN
assets/animations/hall/lounge-chair-v5.bin
Normal file
100
assets/animations/hall/manifest-furniture-v5.json
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
{
|
||||
"card-table": {
|
||||
"size": [
|
||||
320,
|
||||
208
|
||||
],
|
||||
"bounds": [
|
||||
914,
|
||||
407,
|
||||
1240,
|
||||
618
|
||||
],
|
||||
"frames": 1
|
||||
},
|
||||
"roulette-table": {
|
||||
"size": [
|
||||
288,
|
||||
268
|
||||
],
|
||||
"bounds": [
|
||||
0,
|
||||
633,
|
||||
309,
|
||||
919
|
||||
],
|
||||
"frames": 1
|
||||
},
|
||||
"backroom-table": {
|
||||
"size": [
|
||||
304,
|
||||
236
|
||||
],
|
||||
"bounds": [
|
||||
314,
|
||||
686,
|
||||
612,
|
||||
918
|
||||
],
|
||||
"frames": 1
|
||||
},
|
||||
"skill-cabinet": {
|
||||
"size": [
|
||||
224,
|
||||
368
|
||||
],
|
||||
"bounds": [
|
||||
210,
|
||||
0,
|
||||
635,
|
||||
585
|
||||
],
|
||||
"frames": 1
|
||||
},
|
||||
"lounge-chair": {
|
||||
"size": [
|
||||
240,
|
||||
256
|
||||
],
|
||||
"bounds": [
|
||||
907,
|
||||
42,
|
||||
1410,
|
||||
579
|
||||
],
|
||||
"frames": 1
|
||||
},
|
||||
"lamp-table": {
|
||||
"size": [
|
||||
192,
|
||||
224
|
||||
],
|
||||
"bounds": [
|
||||
241,
|
||||
584,
|
||||
627,
|
||||
1024
|
||||
],
|
||||
"frames": 1
|
||||
},
|
||||
"velvet-rope": {
|
||||
"size": [
|
||||
288,
|
||||
192
|
||||
],
|
||||
"bounds": [
|
||||
860,
|
||||
584,
|
||||
1439,
|
||||
1024
|
||||
],
|
||||
"frames": 1
|
||||
},
|
||||
"slot-cabinets": {
|
||||
"size": [
|
||||
224,
|
||||
256
|
||||
],
|
||||
"frames": 3
|
||||
}
|
||||
}
|
||||
BIN
assets/animations/hall/roulette-table-v5.bin
Normal file
BIN
assets/animations/hall/skill-cabinet-v5.bin
Normal file
BIN
assets/animations/hall/slot-cabinets-v5.bin
Normal file
BIN
assets/animations/hall/velvet-rope-v5.bin
Normal file
BIN
assets/animations/slots/cabinet-v1.bin
Normal file
21
assets/animations/slots/manifest.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"symbols": [
|
||||
"seven",
|
||||
"cherries",
|
||||
"lemon",
|
||||
"bell",
|
||||
"BAR",
|
||||
"grapes",
|
||||
"diamond",
|
||||
"crown"
|
||||
],
|
||||
"cabinet": [
|
||||
640,
|
||||
480
|
||||
],
|
||||
"symbol": [
|
||||
64,
|
||||
64
|
||||
],
|
||||
"pipeline": "offline normalization only; gameplay and reel animation are MASM"
|
||||
}
|
||||
BIN
assets/animations/slots/symbols-v1.bin
Normal file
BIN
assets/animations/wheel/closeup-v1.bin
Normal file
42
assets/animations/wheel/manifest-v1.json
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"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
|
||||
],
|
||||
"zero_pockets": 1
|
||||
}
|
||||
BIN
assets/animations/wheel/rotor-v1.bin
Normal file
BIN
assets/animations/wheel/rotor-v2.bin
Normal file
BIN
assets/animations/wheel/table-v1.bin
Normal file
255
assets/data/ui-ru.json
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
{
|
||||
"coinTitle3D": "МОНЕТКА",
|
||||
"coinHeadsText3D": "ОРЁЛ",
|
||||
"coinTailsText3D": "РЕШКА",
|
||||
"coinFlipText3D": "БРОСОК",
|
||||
"coinAgainText3D": "ЕЩЁ РАЗ",
|
||||
"coinExitText3D": "ВЫХОД",
|
||||
"coinBankText3D": "БАНК $",
|
||||
"coinStakeText3D": "СТАВКА",
|
||||
"coinReturnText3D": "ВЫПЛАТА",
|
||||
"coinLeavingText3D": "ВЫХОД ПОСЛЕ БРОСКА",
|
||||
"coinTossText3D": "В ПОЛЁТЕ",
|
||||
"coinLandingText3D": "ПРИЗЕМЛЕНИЕ",
|
||||
"coinPrepareText3D": "БРОСАЕМ",
|
||||
"coinMissingText3D": "НЕТ СПРАЙТОВ",
|
||||
"coinLowBankText3D": "МАЛО ФИШЕК",
|
||||
"wheelBetView3D": "СТАВКИ",
|
||||
"wheelExitText3D": "ВЫХОД",
|
||||
"wheelSpinningText3D": "СТАВКИ ЗАКРЫТЫ",
|
||||
"wheelLeavingText3D": "ВЫХОД ПОСЛЕ ВРАЩЕНИЯ",
|
||||
"wheelResultText3D": "ЧИСЛО",
|
||||
"wheelMissingArt3D": "НЕТ СПРАЙТОВ РУЛЕТКИ",
|
||||
"wheelRed3D": "КРАСН",
|
||||
"wheelBlack3D": "ЧЁРН",
|
||||
"wheelEven3D": "ЧЁТ",
|
||||
"wheelOdd3D": "НЕЧЁТ",
|
||||
"wheelColumn13D": "РЯД 1",
|
||||
"wheelColumn23D": "РЯД 2",
|
||||
"wheelColumn33D": "РЯД 3",
|
||||
"wheelTitle3D": "ЕВРОПЕЙСКАЯ РУЛЕТКА",
|
||||
"wheelSpin3D": "КРУТИТЬ",
|
||||
"wheelClear3D": "СБРОС",
|
||||
"wheelAmountText3D": "ФИШКА $",
|
||||
"wheelStakedText3D": "СТАВКА $",
|
||||
"wheelPaidText3D": "ВЫПЛАТА",
|
||||
"textPause3D": "КАЗИНО / НАСТРОЙКИ",
|
||||
"textResume3D": "ESC - ПРОДОЛЖИТЬ",
|
||||
"textQuit3D": "Q - СОХРАНИТЬ И ВЫЙТИ",
|
||||
"textDisplayFill3D": "1 ЭКРАН: ВЕСЬ МОНИТОР",
|
||||
"textDisplayFit3D": "1 ЭКРАН: КЛАССИКА 4:3",
|
||||
"textLowSpec3D": "2 РЕЖИМ",
|
||||
"textSoundLevel3D": "ГРОМКОСТЬ",
|
||||
"textVolumeKeys3D": "+ / - ГРОМКОСТЬ",
|
||||
"textFullscreenKey3D": "F11 ПОЛНЫЙ ЭКРАН / ОКНО",
|
||||
"textLowSpecOff3D": "ПОЛНЫЙ",
|
||||
"textLowSpecEco3D": "ЭКО",
|
||||
"textLowSpecQuiet3D": "ТИХИЙ",
|
||||
"textMissing3D": "Не удалось загрузить assets/textures/casino3d-hd.bin. Папка assets должна находиться рядом с игрой.",
|
||||
"textWalkKeys3D": "W/S: ХОД A/D: ПОВОРОТ E: ДЕЙСТВИЕ",
|
||||
"textWindowKeys3D": "F11 ЭКРАН / ESC",
|
||||
"textBank3D": "БАНК $",
|
||||
"textTip3D": "ЧАЕВЫЕ $100",
|
||||
"textUnavailable3D": "ПОКА НЕ РЕАЛИЗОВАНО",
|
||||
"textSlots3D": "777 / АВТОМАТ",
|
||||
"textSlotsKeys3D": "ПРОБЕЛ: ИГРА ВВЕРХ/ВНИЗ: СТАВКА",
|
||||
"textBack3D": "ESC: НАЗАД В КАЗИНО",
|
||||
"textBet3D": "СТАВКА $",
|
||||
"textDealer3D": "ДИЛЕР",
|
||||
"textPlayer3D": "ВАШИ КАРТЫ",
|
||||
"textBJKeys3D": "H: КАРТА S: ХВАТИТ",
|
||||
"textDeal3D": "ПРОБЕЛ: СДАТЬ ВВЕРХ/ВНИЗ: СТАВКА",
|
||||
"textNext3D": "ПРОБЕЛ: СЛЕДУЮЩАЯ РАЗДАЧА",
|
||||
"textRed3D": "1 КРАСНОЕ",
|
||||
"textBlack3D": "2 ЧЁРНОЕ",
|
||||
"textZero3D": "3 НОЛЬ",
|
||||
"textEven3D": "4 ЧЁТ",
|
||||
"textOdd3D": "5 НЕЧЁТ",
|
||||
"textSpin3D": "ПРОБЕЛ: ИГРА ESC: ВЫХОД",
|
||||
"textResult3D": "ЧИСЛО",
|
||||
"textShop3D": "МАГАЗИН КАЗИНО",
|
||||
"textItem1_3D": "1 ЗОЛОТАЯ РУБАШКА - $1000",
|
||||
"textItem2_3D": "2 ИЗУМРУДНАЯ РУБАШКА - $1500",
|
||||
"textItem3_3D": "3 БАГРОВАЯ РУБАШКА - $1500",
|
||||
"textShopHint3D": "КУПИТЬ / ВЫБРАТЬ РУБАШКУ",
|
||||
"textBought3D": "РУБАШКА ВЫБРАНА",
|
||||
"textATM3D": "КАССА",
|
||||
"textATMNote3D": "БАЛАНС СОХРАНЯЕТСЯ ПРИ ВЫХОДЕ",
|
||||
"textATMNote2_3D": "ЛОКАЛЬНЫЙ ПРОФИЛЬ ИГРОКА",
|
||||
"textNoCash3D": "НЕДОСТАТОЧНО ФИШЕК",
|
||||
"textWin3D": "ВЫИГРЫШ",
|
||||
"textLose3D": "ПРОИГРЫШ",
|
||||
"textTie3D": "НИЧЬЯ",
|
||||
"textBJ3D": "21 / БЛЭКДЖЕК",
|
||||
"textTips3D": "СПАСИБО ЗА ЧАЕВЫЕ",
|
||||
"entryWelcome3D": "ВХОД В КАЗИНО",
|
||||
"entryChoose3D": "ВАШ ПРОФИЛЬ",
|
||||
"entryGuest3D": "ГОСТЬ",
|
||||
"entryNew3D": "+ НОВЫЙ ИГРОК",
|
||||
"entryNameText3D": "ИМЯ ИГРОКА",
|
||||
"entryConfirm3D": "ВОЙТИ",
|
||||
"entryCancel3D": "ESC: НАЗАД",
|
||||
"entryContinue3D": "ДОБРО ПОЖАЛОВАТЬ",
|
||||
"entryProfileError3D": "СБОЙ ЗАГРУЗКИ",
|
||||
"entryNameError3D": "ИМЯ ЗАНЯТО / СБОЙ",
|
||||
"entryStop3D": "ОДНУ МИНУТУ.",
|
||||
"entryChecking3D": "ПРОВЕРЯЕМ СПИСОК ГОСТЕЙ",
|
||||
"entryReady3D": "ПРОХОДИТЕ.",
|
||||
"entrySkip3D": "ENTER: ПОДОЙТИ",
|
||||
"hallBarPrompt3D": "E: КОКТЕЙЛЬНЫЙ БАР",
|
||||
"hallBunkerPrompt3D": "E: ПОДВАЛ / МАГАЗИН",
|
||||
"hallUpPrompt3D": "E: НАВЕРХ",
|
||||
"hallPoolPrompt3D": "E: БИЛЬЯРД",
|
||||
"barName3D": "БАР СТАРОГО ГОРОДА",
|
||||
"barDrinks3D": "1 ХАЙБОЛ $100",
|
||||
"barDrinks23D": "2 КОКТЕЙЛЬ $200",
|
||||
"barDrinks33D": "3 ВОДА $0",
|
||||
"barPoor3D": "МАЛО ФИШЕК",
|
||||
"barMixText3D": "СМЕШИВАЕМ",
|
||||
"barDrinkText3D": "ВАШЕ ЗДОРОВЬЕ",
|
||||
"merchantGrey3D": "СЕРЕБРО",
|
||||
"merchantBlue3D": "САПФИРОВАЯ ВОЛНА",
|
||||
"merchantRed3D": "БАГРОВЫЙ КРЕСТ",
|
||||
"merchantGold3D": "ЗОЛОТОЕ СОЛНЦЕ",
|
||||
"merchantSkull3D": "ЧЕРЕП И РОЗЫ",
|
||||
"merchantClover3D": "КЛЕВЕР",
|
||||
"merchantArcane3D": "АРКАНА",
|
||||
"merchantNoir3D": "НУАР",
|
||||
"merchantDiamond3D": "АЛМАЗ",
|
||||
"merchantRider3D": "НАЕЗДНИК",
|
||||
"merchantBee3D": "ПЧЕЛА",
|
||||
"merchantFan3D": "ВЕЕР",
|
||||
"merchantWeb3D": "ПАУТИНА",
|
||||
"merchantTitle3D": "СИДОРОВИЧ",
|
||||
"merchantStock3D": "РУБАШКИ",
|
||||
"merchantBuy3D": "КУПИТЬ",
|
||||
"merchantOwned3D": "ЕСТЬ",
|
||||
"merchantEquipped3D": "НАДЕТО",
|
||||
"merchantPoor3D": "МАЛО ФИШЕК",
|
||||
"merchantShopKeys3D": "ВВЕРХ/ВНИЗ ENTER: КУПИТЬ ESC: ХОЛЛ",
|
||||
"merchantHello3D": "ПОСМОТРИ, ЧТО ЕСТЬ.",
|
||||
"merchantThanks3D": "ХОРОШИЙ ВЫБОР.",
|
||||
"pkTitle3D": "ТЕХАССКИЙ ХОЛДЕМ",
|
||||
"pkPotText3D": "БАНК",
|
||||
"pkStreet0Text3D": "ПРЕФЛОП",
|
||||
"pkStreet1Text3D": "ФЛОП",
|
||||
"pkStreet2Text3D": "ТЁРН",
|
||||
"pkStreet3Text3D": "РИВЕР",
|
||||
"pkCheckText3D": "ПАС",
|
||||
"pkCallText3D": "УРАВНЯТЬ",
|
||||
"pkRaiseText3D": "ПОВЫСИТЬ",
|
||||
"pkFoldText3D": "СБРОС",
|
||||
"pkAllInText3D": "ВА-БАНК",
|
||||
"pkCostText3D": "КОЛЛ",
|
||||
"pkMinimumText3D": "МИН. РЕЙЗ",
|
||||
"pkDealText3D": "СДАТЬ",
|
||||
"pkNextText3D": "ДАЛЕЕ",
|
||||
"pkAiWait3D": "ДИЛЕР",
|
||||
"pkAiCheck3D": "ПАС",
|
||||
"pkAiCall3D": "КОЛЛ",
|
||||
"pkAiRaise3D": "РЕЙЗ",
|
||||
"pkAiFold3D": "СБРОС",
|
||||
"pkWinText3D": "ВЫ ВЫИГРАЛИ",
|
||||
"pkLoseText3D": "ДИЛЕР ВЫИГРАЛ",
|
||||
"pkTieText3D": "БАНК ПОРОВНУ",
|
||||
"pkRank0": "СТАРШАЯ КАРТА",
|
||||
"pkRank1": "ПАРА",
|
||||
"pkRank2": "ДВЕ ПАРЫ",
|
||||
"pkRank3": "ТРОЙКА",
|
||||
"pkRank4": "СТРИТ",
|
||||
"pkRank5": "ФЛЕШ",
|
||||
"pkRank6": "ФУЛЛ-ХАУС",
|
||||
"pkRank7": "КАРЕ",
|
||||
"pkRank8": "СТРИТ-ФЛЕШ",
|
||||
"cbTitle3D": "БЛЭКДЖЕК / 21",
|
||||
"cbHitText3D": "КАРТА",
|
||||
"cbStandText3D": "ХВАТИТ",
|
||||
"cbDoubleText3D": "УДВОИТЬ",
|
||||
"cbNaturalText3D": "БЛЭКДЖЕК",
|
||||
"tableBlindText3D": "БЛАЙНД $",
|
||||
"tableRaiseText3D": "РЕЙЗ +$",
|
||||
"tableScoreText3D": "ОЧКИ",
|
||||
"bs3d_textTitle": "БАКШОТ",
|
||||
"bs3d_textBank": "БАНК $",
|
||||
"bs3d_textPlayer": "ИГРОК",
|
||||
"bs3d_textDealer": "ДИЛЕР",
|
||||
"bs3d_textBet": "СТАВКА $",
|
||||
"bs3d_textReady": "ПРОБЕЛ: ИГРАТЬ",
|
||||
"bs3d_textResult": "ПРОБЕЛ: ЕЩЁ РАЗ",
|
||||
"bs3d_textExit": "ESC: ХОЛЛ",
|
||||
"bs3d_textPause": "ESC: ПАУЗА",
|
||||
"bs3d_textChoose": "1: В СЕБЯ",
|
||||
"bs3d_textOpponent": "2: В ДИЛЕРА",
|
||||
"bs3d_textWin": "ВЫ ВЫИГРАЛИ",
|
||||
"bs3d_textLose": "ДИЛЕР ВЫИГРАЛ",
|
||||
"bs3d_textLoad": "ПЕРЕЗАРЯДКА",
|
||||
"bs3d_textLive": "БОЕВЫЕ",
|
||||
"bs3d_textBlank": "ХОЛОСТЫЕ",
|
||||
"bs3d_textShells": "ПАТРОНЫ",
|
||||
"bs3d_textEmpty": "МАЛО ДЕНЕГ",
|
||||
"bs3d_textShot": "БОЕВОЙ ПАТРОН",
|
||||
"bs3d_textDry": "ХОЛОСТОЙ ПАТРОН",
|
||||
"bs3d_textKnownLive": "СЛЕДУЮЩИЙ: БОЕВОЙ",
|
||||
"bs3d_textKnownBlank": "СЛЕДУЮЩИЙ: ХОЛОСТОЙ",
|
||||
"bs3d_textSaw": "УРОН СЛЕДУЮЩЕГО ВЫСТРЕЛА x2",
|
||||
"bs3d_textBeer": "ПАТРОН ВЫБРОШЕН",
|
||||
"bs3d_textCuffs": "ПРОТИВНИК ПРОПУСКАЕТ ХОД",
|
||||
"bs3d_textItemEmpty": "ПРЕДМЕТ НЕДОСТУПЕН",
|
||||
"bs3d_textWait": "ХОД ДИЛЕРА",
|
||||
"bs3d_textItem": "ИСПОЛЬЗУЕМ ПРЕДМЕТ",
|
||||
"bs3d_textAssets": "АНИМАЦИЯ НЕ НАЙДЕНА ИЛИ ПОВРЕЖДЕНА",
|
||||
"bs3d_textMedical": "МЕДИЦИНСКАЯ МАШИНА: РЕАНИМАЦИЯ",
|
||||
"bs3d_textDeath": "ЖИЗНЕННЫЙ СИГНАЛ ПОТЕРЯН",
|
||||
"bs3d_textGlassKey": "3: ЛУПА",
|
||||
"bs3d_textSawKey": "4: ПИЛА",
|
||||
"bs3d_textBeerKey": "5: ПИВО",
|
||||
"bs3d_textCuffKey": "6:ОКОВЫ",
|
||||
"poolTitle3D": "ПУЛ / 8",
|
||||
"poolPlayerText3D": "ИГРОК",
|
||||
"poolDealerText3D": "ДИЛЕР",
|
||||
"poolOpenText3D": "СТОЛ ОТКРЫТ",
|
||||
"poolSolidsText3D": "СПЛОШНЫЕ",
|
||||
"poolStripesText3D": "ПОЛОСАТЫЕ",
|
||||
"poolFoulText3D": "ФОЛ / С РУКИ",
|
||||
"poolWinText3D": "ПОБЕДА",
|
||||
"poolShotText3D": "УДАР",
|
||||
"poolRackText3D": "ЗАНОВО",
|
||||
"poolPowerText3D": "СИЛА",
|
||||
"poolPlaceText3D": "ПОСТАВЬТЕ БИТОК",
|
||||
"poolMovingText3D": "КАТЯТСЯ",
|
||||
"poolBallText3D": "ШАР",
|
||||
"poolPocketText3D": "ЛУЗА",
|
||||
"startupEnter3D": "ENTER",
|
||||
"promptPoker": "[E] ПОКЕР (ТЕХАССКИЙ ХОЛДЕМ)",
|
||||
"promptDice": "[E] ИГРА В КОСТИ",
|
||||
"promptBuckshot": "[E] БАКШОТ РУЛЕТКА",
|
||||
"textDiceTitle": "ИГРА В КОСТИ",
|
||||
"textSkillTitle": "=== ПРОВЕРКА НАВЫКА ===",
|
||||
"textSkillGreatMsg": "ОТЛИЧНО! +БОНУС!",
|
||||
"strPush": "НИЧЬЯ",
|
||||
"sz3DWindowTitle": "Ассемблер Казино - 2.5D",
|
||||
"szTitleBlackjack": "КАЗИК 3D - БЛЭКДЖЕК (21)",
|
||||
"szTitlePoker": "КАЗИК 3D - ПОКЕР (ТЕХАССКИЙ ХОЛДЕМ)",
|
||||
"szTitleDurak": "КАЗИК 3D - ПЕРЕВОДНОЙ ДУРАК",
|
||||
"szTitleCasinoRoulette": "КАЗИК 3D - ЕВРОПЕЙСКАЯ РУЛЕТКА",
|
||||
"szTitleClassicSlot": "КАЗИК 3D - АВТОМАТ 777",
|
||||
"szTitleCloverSlot": "КАЗИК 3D - КЛЕВЕРНАЯ ЯМА (5x3)",
|
||||
"szTitleDice": "КАЗИК 3D - ИГРА В КОСТИ",
|
||||
"szTitleSkulls": "КАЗИК 3D - НАПЁРСТКИ",
|
||||
"szTitleCoin": "КАЗИК 3D - МОНЕТКА (ОРЁЛ/РЕШКА)",
|
||||
"szTitleSkillCheck": "КАЗИК 3D - ПРОВЕРКА НАВЫКА",
|
||||
"szTitleBuckshot": "КАЗИК 3D - БАКШОТ РУЛЕТКА",
|
||||
"szTitleRussianRoulette": "КАЗИК 3D - РУССКАЯ РУЛЕТКА",
|
||||
"szTitleOnlineRR": "КАЗИК 3D - СЕТЕВАЯ РУССКАЯ РУЛЕТКА",
|
||||
"szTitleUmamusume": "КАЗИК 3D - ГОНКИ УМАМУСУМЕ",
|
||||
"szTitleHellTower": "КАЗИК 3D - АДСКАЯ БАШНЯ",
|
||||
"szTitleShop": "КАЗИК 3D - КАРТЫ И ТАЛИСМАНЫ",
|
||||
"szTitleATM": "КАЗИК 3D - БАНКОМАТ",
|
||||
"szTitleTerminal": "КАЗИК 3D - ЛОКАЛЬНЫЕ ПРОФИЛИ",
|
||||
"szTitleObserver": "КАЗИК 3D - НАБЛЮДАТЕЛЬ (ИИ)",
|
||||
"symBell": " ЗВОН",
|
||||
"symCherry": "ВИШНЯ",
|
||||
"symClover": "КЛЕВЕР",
|
||||
"symGem": "АЛМАЗ",
|
||||
"symCrown": "КОРОНА"
|
||||
}
|
||||
BIN
assets/sprites/coin/faces-v1.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
assets/sprites/coin/hands-v1.png
Normal file
|
After Width: | Height: | Size: 847 KiB |
BIN
assets/sprites/coin/hands-v2.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
6
assets/sprites/coin/prompts-v1.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"tool": "image_gen",
|
||||
"table": "Production background for a playable first-person coin toss casino mini-game, 4:3 landscape 640x480 composition. Detailed hand-crafted late-1990s pixel art, sharp pixels, rich textured surfaces, not a photograph and not low-poly. Match a burgundy velvet, green felt, brass and dark carved wood retro casino. POV seated player looking down at a small green felt gaming table with thick polished wood rim. The lower 70% is broad unobstructed felt, especially the center at 50% width 65% height for a dynamically tossed coin. Across the table in upper third is a dignified male dealer in white shirt and burgundy waistcoat, head fully visible with comfortable margin at least 12% image height from top, his hands BELOW the table out of sight. Background wall panels and warm lamps, distant casino chairs, coherent perspective, no crowd. Few chip stacks at left and right corners, not in center. No coin, no player's hands, no baked shadows in central play area, no lettering, no digits, no markings, no interface, no logos. This is game environment art, not an illustration in a frame.",
|
||||
"faces": "A production sprite sheet on genuinely transparent background for a detailed late-1990s pixel art casino coin toss game. Exactly TWO separate gold coin faces, arranged left-to-right in one horizontal row with wide transparent gap and generous transparent margins. Orthographic straight-on circular views of the SAME antique solid gold casino token, embossed detailed relief, thick finely reeded edge, high contrast dark recesses and restrained polished highlights. LEFT coin has a crowned eagle relief (HEADS). RIGHT coin has a large embossed five-point star in a wreath (TAILS). No lettering, no digits, no table, no hands, no environment, no drop shadows outside circular boundary. Pixel-art material texture and clearly distinguishable symbols, NOT photorealism, NOT emoji or flat icon. Both coins exactly same diameter, palette, lighting from upper left, centered at same height, complete uncropped silhouettes; perfect circles in frontal view. Do not add extra coins or tiny examples.",
|
||||
"hands": "Production sprite sheet, genuinely transparent background, exactly 8 poses in a regular 4-column by 2-row grid, wide transparent gutters between every cell. A first-person PLAYER'S RIGHT HAND emerging from bottom right, detailed late-1990s textured pixel art, bare light skin and black leather coat cuff, matching a retro 2.5D casino game. Every cell contains ONLY one complete wrist/cuff and hand, same hand anatomy, same scale and same lighting from upper left, no environment, no text, no grid lines, no second hand. Sequence read left-to-right then next row: pose 1 fingers curled and THUMB curled below an imaginary coin; pose 2 thumb cocked against index finger; pose 3 thumb beginning upward flick; pose 4 thumb extended after releasing imaginary coin; pose 5 fingers open in follow-through; pose 6 fingers relaxed as hand draws back; pose 7 relaxed hand half withdrawn downward; pose 8 relaxed hand withdrawn pose. No actual coin in any pose because it is rendered separately. No knife, no cigarette, no gun, no gloves, no sleeves other than dark cuff. Maintain a common wrist anchor at same place within each cell and natural palm facing upper-left toward center of screen. Hand should fit the bottom-right corner of a first-person screen, not point at the viewer. Complete cutouts, no clipping by cell boundaries. Smooth progression of real distinct poses."
|
||||
}
|
||||
6
assets/sprites/coin/prompts-v2.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"tool": "image_gen",
|
||||
"prompt": "Use case: precise-object-edit / game sprite animation. Input image is a style and character-hand reference, NOT a layout to copy. Create a NEW production sprite sheet with exactly SIXTEEN equal square cells in a 4 columns by 4 rows grid, left-to-right top-to-bottom chronological order, true transparent background and no separators, labels, lettering or shadows on the empty background. Same first-person RIGHT human hand, natural anatomy, five fingers, black leather jacket cuff, warm light from upper left, detailed late-1990s pixel-art look matching the reference. Same scale, camera and wrist origin in EVERY cell; wrist cropped at lower-right corner, all fingers fully inside cell with ample clear alpha margin. Animate a physically convincing coin toss with the THUMB, not a pinch-and-drop. Frames 0-5: a small gold coin (diameter about one thumbnail width) is drawn AS PART OF THE SPRITE resting FLAT DIRECTLY ON THE THUMBNAIL, supported by the thumb while the other fingers curl; coin is horizontal and its edge visible, no gap between thumbnail and coin, no coin poking through fingers. Six VERY SMALL intermediate changes: thumb bends down/cocks, then springs upward; same wrist, same coin contact, no teleport. Frames 6-8: thumb finishes snapping upward, the coin has LEFT THE HAND and MUST NOT APPEAR anywhere in these or any later cells; fingers open only slightly, NOT a waving open palm. Frames 9-15: empty hand relaxes and smoothly withdraws down toward the lower-right edge in seven subtly different intermediate poses. NO airborne coins drawn anywhere. First six coins neutral embossed gold, no face/letter readability needed. Keep reference skin and leather texture but remove the red halo around the silhouette. Clean alpha boundary, no red outlines, no second hands, no extra limbs. This will be composited over a green casino table; the coin in flight is rendered separately by the assembly engine.",
|
||||
"reference": "assets/sprites/coin/hands-v1.png",
|
||||
"output": "assets/sprites/coin/hands-v2.png"
|
||||
}
|
||||
BIN
assets/sprites/coin/table-v1.png
Normal file
|
After Width: | Height: | Size: 2.4 MiB |
BIN
assets/sprites/hall/furniture-v5.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
4
assets/sprites/hall/prompts-v5.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"tool": "image_gen",
|
||||
"prompt": "Create a production sprite sheet for a detailed retro 2.5D first-person casino game, all four objects fully isolated on true transparent background, a strict 2 columns by 2 rows grid with very generous transparent gutters. Matching late-1990s richly textured pixel-art sprites, NOT photorealistic or smooth vector. Burgundy leather, aged brass, dark wood, restrained emerald. Front three-quarter view, camera at standing human eye height, complete floor-to-top objects, crisp pixels. TOP LEFT: a tall industrial skill-check arcade cabinet, complete curved upper housing with a circular illuminated green timing dial, mechanical hook emblem, orange-red light column, physical button control pedestal and wide stable metal base; all upper and lower parts must be present, no blood, no person. TOP RIGHT: an elegant high-backed burgundy leather armchair with carved dark wooden legs, complete chair. BOTTOM LEFT: a small round dark wooden side table with one lit brass shaded table lamp and a whiskey tumbler, complete table legs. BOTTOM RIGHT: two brass stanchions joined by a burgundy velvet rope, complete circular floor bases. Every object separate and complete, never crosses its cell; NO other objects, NO human limbs, NO lettering, NO background floor or room, no cast shadow outside sprite."
|
||||
}
|
||||
BIN
assets/sprites/slots/cabinet-v1.png
Normal file
|
After Width: | Height: | Size: 2.4 MiB |
5
assets/sprites/slots/prompts-v1.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"tool": "built-in image_gen",
|
||||
"cabinet": "Use case: stylized-concept. Asset type: finished 4:3 first-person casino game environment background, native 640x480 retro software-rendered game. Detailed cohesive late-1990s pixel art, deliberately drawn clusters, crisp edges and textured shaded metal, NOT photorealistic, NOT blurry, no UI mockup. Straight-on close view of one vintage mechanical slot machine, centered, complete cabinet with dark red enamel, aged brass trim, chrome, amber bulbs, black ribbed sides, a chunky lever on the right and coin tray below. In a richly furnished casino, other machines and red upholstered chairs only at far margins. Top marquee has exactly \"777\". Three tall EMPTY ivory reel windows side by side dominate center, reserved for moving symbols rendered by the game, absolutely NO reel symbols inside. Dark inset blank plate below reels for a digital counter, red mechanical round spin button underneath. Layout on a 640x480 target: machine fills x=78..562,y=38..452; three empty windows jointly x=148..492,y=146..298; there is space above machine y<38 for HUD and below y>442 for game buttons, coin tray visible lower down. No hands, no people, no additional labels or text. Single coherent depth, frontal reels without perspective skew, premium legible game art matching wooden/red/green pixel-art casino interiors.",
|
||||
"symbols": "Use case: stylized-concept. Asset type: production transparent game sprite atlas, exactly eight icons in a strict equal 4-column by 2-row grid, square image 1024x1024, each cell256x512? No: canvas should be landscape 2048x1024 with eight square512x512 cells, four across and two down. Transparent background, no borders, no labels, no shadows outside icon silhouettes, no text except BAR. Each icon centered in its cell with generous identical safe padding, consistent large scale about300 pixels. Row1 left to right: a single ornate RED SEVEN number7 outlined in gold; two glossy red cherries on green stems; one bright yellow lemon with a green leaf; a polished golden bell. Row2 left to right: a traditional black rectangular casino BAR plaque with exactly \"BAR\" in warm white; one bunch of purple grapes with leaf; a faceted cyan diamond jewel; a gold royal crown with ruby insets. Late-1990s richly detailed retro pixel art, deliberate crisp pixel clusters, shaded jewel/enamel surfaces matching vintage slot-machine reel printing, not vector art, not smooth modern illustrations, not photorealistic. Eight isolated symbols only, equal framing, nothing overlaps cell boundaries, no perspective background. These are reel sprites for a dark-red/brass mechanical slot cabinet."
|
||||
}
|
||||
BIN
assets/sprites/slots/symbols-v1.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/sprites/wheel/closeup-v1.png
Normal file
|
After Width: | Height: | Size: 2.3 MiB |
5
assets/sprites/wheel/prompts-v1.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"tool": "image_gen",
|
||||
"wide": "Generate a production 640x480 aspect-ratio opaque background for a first-person European roulette scene in a richly detailed late-1990s pixel-art casino, matching burgundy leather, green felt, aged brass, polished dark wood interior. POV a player seated at roulette table. Composition precise: left half/top part contains an EMPTY oval roulette wooden bowl, center at 31% image width and 27% image height, outer size 53% image width and 34% image height; no rotating rotor and NO numbers in the empty bowl, those will be rendered dynamically by game code. A formally dressed male croupier stands across the table in the upper RIGHT quarter, his head and upper torso visible above the tabletop, one open hand inviting bets, no playing cards. Green felt table fills lower half and will be covered by native betting UI. Several stacks of red/white/blue chips near outer corners, NOT inside the bowl. Background soft-focus burgundy wall panels, warm brass wall lights and rail. Crisp hand-crafted textured pixel art, coherent perspective, NOT photograph, NOT low-poly, no lettering, no UI, no overlay, no logos, no extra hands, no static ball, NO painted betting numbers or fake roulette wheel markings.",
|
||||
"closeup": "Edit this roulette background into a second camera angle of the SAME table and SAME casino, used during a spin. Preserve the exact detailed retro pixel-art style, colors, male croupier identity and wooden bowl materials. Bring the camera smoothly closer and angle down at the wheel. Empty inner wheel bowl is centered at 50% image width and 57% image height, its INNER rim ellipse covers from 12% to 88% image width horizontally, 30% to 86% image height vertically. Entire oval wheel housing fits within the image, not cropped, large across the center. Croupier is in the upper right BACKGROUND, much smaller and behind the bowl, not in front of it. Leave the bowl completely empty so exact numbered rotating rotor and ball can be drawn by code. No roulette numerals, no letters, no ball, no interface, no playing cards, no translucent overlay. Green felt surrounds the wooden housing; warm lamps and burgundy casino interior in the background."
|
||||
}
|
||||
BIN
assets/sprites/wheel/table-v1.png
Normal file
|
After Width: | Height: | Size: 2.3 MiB |
BIN
bin/poker.exe
|
|
@ -8,7 +8,7 @@ namespace AssemblerCasinoLauncher
|
|||
{
|
||||
static class Program
|
||||
{
|
||||
const string ExpectedPokerSha256 = "2AA5FB60E0E1BE3366B690166FDD63A7E589ED6674F23F057BD500C8D97092E4";
|
||||
const string ExpectedPokerSha256 = "6DE8E29E8A8FCC60C2FB297348BAD5E20697611317EF53C7E5A258BDCADAB657";
|
||||
|
||||
[STAThread]
|
||||
static void Main()
|
||||
|
|
|
|||
98
casino3d.inc
|
|
@ -151,6 +151,8 @@ include src_graphics\billiards_data.inc
|
|||
include src_graphics\buckshot_data.inc
|
||||
include src_graphics\russian_view_data.inc
|
||||
include src_graphics\unavailable_data.inc
|
||||
include src_graphics\native_slots_data.inc
|
||||
include src_graphics\native_coin_data.inc
|
||||
|
||||
.data
|
||||
ALIGN 4
|
||||
|
|
@ -164,7 +166,7 @@ msg3D C3D_MSG <>
|
|||
wc3D C3D_WNDCLASSEX <>
|
||||
|
||||
sz3DClassName db "Casino3DRetroClass",0
|
||||
sz3DWindowTitle db "Assembler Casino - 2.5D",0
|
||||
sz3DWindowTitle db 192,241,241,229,236,225,235,229,240,32,202,224,231,232,237,238,32,45,32,50,46,53,68,0
|
||||
szTexturesRelPath db "assets\textures\casino3d-hd.bin",0
|
||||
szTexturesFullPath db 260 dup(0)
|
||||
|
||||
|
|
@ -186,16 +188,16 @@ flashMessage db 128 dup(0)
|
|||
|
||||
promptDancer db "[E] ÊÀÁÀÐÅ - ×ÀÅÂÛÅ $100",0
|
||||
promptBlackjack db "[E] ÁËÝÊÄÆÅÊ (21)",0
|
||||
promptPoker db "[E] ÏÎÊÅÐ (TEXAS HOLD'EM)",0
|
||||
promptPoker db 91,69,93,32,207,206,202,197,208,32,40,210,197,213,192,209,209,202,200,201,32,213,206,203,196,197,204,41,0
|
||||
promptDurak db "[E] ÊÀÐÒÛ: ÏÎÄÊÈÄÍÎÉ ÄÓÐÀÊ",0
|
||||
promptCasinoRoulette db "[E] ÅÂÐÎÏÅÉÑÊÀß ÐÓËÅÒÊÀ",0
|
||||
promptClassicSlot db "[E] ÊËÀÑÑÈ×ÅÑÊÈÅ ÑËÎÒÛ 777",0
|
||||
promptCloverSlot db "[E] ÑËÎÒÛ CLOVERPIT (5x3)",0
|
||||
promptDice db "[E] ÈÃÐÀ Â ÊÎÑÒÈ (CRAPS)",0
|
||||
promptDice db 91,69,93,32,200,195,208,192,32,194,32,202,206,209,210,200,0
|
||||
promptSkulls db "[E] ÍÀϨÐÑÒÊÈ (×ÅÐÅÏÀ)",0
|
||||
promptCoin db "[E] ÌÎÍÅÒÊÀ (ÎШË/ÐÅØÊÀ)",0
|
||||
promptSkillCheck db "[E] ÒÐÅÍÈÐÎÂÊÀ ÐÅÀÊÖÈÈ",0
|
||||
promptBuckshot db "[E] BUCKSHOT ROULETTE",0
|
||||
promptBuckshot db 91,69,93,32,193,192,202,216,206,210,32,208,211,203,197,210,202,192,0
|
||||
promptRussianRoulette db "[E] ÐÓÑÑÊÀß ÐÓËÅÒÊÀ (VIP)",0
|
||||
promptOnlineRR db "[E] ÑÅÒÅÂÀß ÐÓËÅÒÊÀ (NET)",0
|
||||
promptUmamusume db "[E] ÑÊÀ×ÊÈ ÓÌÀÌÓÑÓÌÝ",0
|
||||
|
|
@ -205,25 +207,27 @@ promptATM db "[E]
|
|||
promptPlayerTerminal db "[E] ÒÅÐÌÈÍÀË: ÑÒÀÒÛ È À×ÈÂÊÈ",0
|
||||
promptObserver db "[E] ÐÅÆÈÌ ÍÀÁËÞÄÀÒÅËß (ÈÈ)",0
|
||||
|
||||
szTitleBlackjack db "[KAZIK 3D CASINO] - ÁËÝÊÄÆÅÊ (21)",0
|
||||
szTitlePoker db "[KAZIK 3D CASINO] - ÏÎÊÅÐ (TEXAS HOLD'EM)",0
|
||||
szTitleDurak db "[KAZIK 3D CASINO] - ÏÎÄÊÈÄÍÎÉ ÄÓÐÀÊ",0
|
||||
szTitleCasinoRoulette db "[KAZIK 3D CASINO] - ÅÂÐÎÏÅÉÑÊÀß ÐÓËÅÒÊÀ",0
|
||||
szTitleClassicSlot db "[KAZIK 3D CASINO] - ÊËÀÑÑÈ×ÅÑÊÈÅ ÑËÎÒÛ 777",0
|
||||
szTitleCloverSlot db "[KAZIK 3D CASINO] - ÑËÎÒ-ÌÀØÈÍÀ CLOVERPIT (5x3)",0
|
||||
szTitleDice db "[KAZIK 3D CASINO] - ÈÃÐÀ Â ÊÎÑÒÈ (CRAPS)",0
|
||||
szTitleSkulls db "[KAZIK 3D CASINO] - ÍÀϨÐÑÒÊÈ",0
|
||||
szTitleCoin db "[KAZIK 3D CASINO] - ÌÎÍÅÒÊÀ (ÎШË/ÐÅØÊÀ)",0
|
||||
szTitleSkillCheck db "[KAZIK 3D CASINO] - ÏÐÎÂÅÐÊÀ ÐÅÀÊÖÈÈ",0
|
||||
szTitleBuckshot db "[KAZIK 3D CASINO] - BUCKSHOT ROULETTE",0
|
||||
szTitleRussianRoulette db "[KAZIK 3D CASINO] - ÐÓÑÑÊÀß ÐÓËÅÒÊÀ",0
|
||||
szTitleOnlineRR db "[KAZIK 3D CASINO] - ÑÅÒÅÂÀß ÐÓÑÑÊÀß ÐÓËÅÒÊÀ",0
|
||||
szTitleUmamusume db "[KAZIK 3D CASINO] - ÑÊÀ×ÊÈ ÓÌÀÌÓÑÓÌÝ",0
|
||||
szTitleHellTower db "[KAZIK 3D CASINO] - ÁÀØÍß ÀÄÀ (ÒÓÐÍÈÐ)",0
|
||||
szTitleShop db "[KAZIK 3D CASINO] - ÁÓÒÈÊ È ÒÀËÈÑÌÀÍÛ",0
|
||||
szTitleATM db "[KAZIK 3D CASINO] - ÁÀÍÊÎÌÀÒ",0
|
||||
szTitleTerminal db "[KAZIK 3D CASINO] - ÒÅÐÌÈÍÀË ÈÃÐÎÊÀ",0
|
||||
szTitleObserver db "[KAZIK 3D CASINO] - ÐÅÆÈÌ ÍÀÁËÞÄÀÒÅËß (ÈÈ)",0
|
||||
szTitleBlackjack db 202,192,199,200,202,32,51,68,32,45,32,193,203,221,202,196,198,197,202,32,40,50,49,41,0
|
||||
szTitlePoker db 202,192,199,200,202,32,51,68,32,45,32,207,206,202,197,208,32,40,210,197,213,192,209,209,202,200,201,32,213,206,203,196
|
||||
db 197,204,41,0
|
||||
szTitleDurak db 202,192,199,200,202,32,51,68,32,45,32,207,197,208,197,194,206,196,205,206,201,32,196,211,208,192,202,0
|
||||
szTitleCasinoRoulette db 202,192,199,200,202,32,51,68,32,45,32,197,194,208,206,207,197,201,209,202,192,223,32,208,211,203,197,210,202,192,0
|
||||
szTitleClassicSlot db 202,192,199,200,202,32,51,68,32,45,32,192,194,210,206,204,192,210,32,55,55,55,0
|
||||
szTitleCloverSlot db 202,192,199,200,202,32,51,68,32,45,32,202,203,197,194,197,208,205,192,223,32,223,204,192,32,40,53,120,51,41,0
|
||||
szTitleDice db 202,192,199,200,202,32,51,68,32,45,32,200,195,208,192,32,194,32,202,206,209,210,200,0
|
||||
szTitleSkulls db 202,192,199,200,202,32,51,68,32,45,32,205,192,207,168,208,209,210,202,200,0
|
||||
szTitleCoin db 202,192,199,200,202,32,51,68,32,45,32,204,206,205,197,210,202,192,32,40,206,208,168,203,47,208,197,216,202,192,41,0
|
||||
szTitleSkillCheck db 202,192,199,200,202,32,51,68,32,45,32,207,208,206,194,197,208,202,192,32,205,192,194,219,202,192,0
|
||||
szTitleBuckshot db 202,192,199,200,202,32,51,68,32,45,32,193,192,202,216,206,210,32,208,211,203,197,210,202,192,0
|
||||
szTitleRussianRoulette db 202,192,199,200,202,32,51,68,32,45,32,208,211,209,209,202,192,223,32,208,211,203,197,210,202,192,0
|
||||
szTitleOnlineRR db 202,192,199,200,202,32,51,68,32,45,32,209,197,210,197,194,192,223,32,208,211,209,209,202,192,223,32,208,211,203,197,210
|
||||
db 202,192,0
|
||||
szTitleUmamusume db 202,192,199,200,202,32,51,68,32,45,32,195,206,205,202,200,32,211,204,192,204,211,209,211,204,197,0
|
||||
szTitleHellTower db 202,192,199,200,202,32,51,68,32,45,32,192,196,209,202,192,223,32,193,192,216,205,223,0
|
||||
szTitleShop db 202,192,199,200,202,32,51,68,32,45,32,202,192,208,210,219,32,200,32,210,192,203,200,209,204,192,205,219,0
|
||||
szTitleATM db 202,192,199,200,202,32,51,68,32,45,32,193,192,205,202,206,204,192,210,0
|
||||
szTitleTerminal db 202,192,199,200,202,32,51,68,32,45,32,203,206,202,192,203,220,205,219,197,32,207,208,206,212,200,203,200,0
|
||||
szTitleObserver db 202,192,199,200,202,32,51,68,32,45,32,205,192,193,203,222,196,192,210,197,203,220,32,40,200,200,41,0
|
||||
textCabinetFooter db "[ ÂÛÕÎÄ: ÂÂÅÄÈÒÅ 0 / ÂÛÁÅÐÈÒÅ 'N' ÄËß ÂÎÇÂÐÀÒÀ Â ÇÀË ]",0
|
||||
|
||||
msgDancerTipped db "Âû áðîñèëè $100 òàíöîâùèöå! ÓÄÀ×À ÀÊÒÈÂÈÐÎÂÀÍÀ!",0
|
||||
|
|
@ -328,7 +332,7 @@ dice3d_val2 dd 6
|
|||
dice3d_sum dd 10
|
||||
dice3d_win dd 0
|
||||
|
||||
textDiceTitle db "GRAND CRAPS",0
|
||||
textDiceTitle db 200,195,208,192,32,194,32,202,206,209,210,200,0
|
||||
textDiceEven db "[1] רÒ",0
|
||||
textDiceOdd db "[2] ÍÅ×ÅÒ",0
|
||||
textDiceEvenNums db "2 4 6 ...",0
|
||||
|
|
@ -390,13 +394,13 @@ skill3d_misses dd 0
|
|||
skill3d_last_result dd 0
|
||||
skill3d_win_amount dd 0
|
||||
|
||||
textSkillTitle db "=== S K I L L C H E C K ===",0
|
||||
textSkillTitle db 61,61,61,32,207,208,206,194,197,208,202,192,32,205,192,194,219,202,192,32,61,61,61,0
|
||||
textSkillHitsHdr db "ÕÈÒ: ",0
|
||||
textSkillMissHdr db "ÏÐÎÌÀÕ: ",0
|
||||
textSkillReadyMsg db "ÍÀÆÌÈÒÅ [ÏÐÎÁÅË] ÄËß ÑÒÀÐÒÀ",0
|
||||
textSkillPrompt db "ÍÀÆÌÈÒÅ [ÏÐÎÁÅË] Â ÇÎÍÅ!",0
|
||||
textSkillHitMsg db "ÕÈÒ! ÒÎ×ÍÎÅ ÏÎÏÀÄÀÍÈÅ!",0
|
||||
textSkillGreatMsg db "ÎÒËÈ×ÍÎ! GREAT SKILL CHECK! +ÁÎÍÓÑ!",0
|
||||
textSkillGreatMsg db 206,210,203,200,215,205,206,33,32,43,193,206,205,211,209,33,0
|
||||
textSkillMissMsg db "ÏÐÎÌÀÕ! ÒÐÅÂÎÃÀ!",0
|
||||
textSkillEscape db "ÏÎÁÅÃ ÓÑÏÅØÅÍ! ÂÛÈÃÐÛØ: +$",0
|
||||
textSkillLost db "ÂÛ ÏÎÉÌÀÍÛ! ÏÐÎÈÃÐÛØ ÑÒÀÂÊÈ!",0
|
||||
|
|
@ -415,17 +419,17 @@ atmMsg db 128 dup(0)
|
|||
strWin db "ÏÎÁÅÄÀ! +$",0
|
||||
strLose db "ÏÐÎÈÃÐÛØ",0
|
||||
strJackpot db "ÄÆÅÊÏÎÒ! +$",0
|
||||
strPush db "ÍÈ×Üß (PUSH)",0
|
||||
strPush db 205,200,215,220,223,0
|
||||
strDealerBust db "ÄÈËÅÐ ÏÅÐÅÁÐÀË! ÏÎÁÅÄÀ! +$",0
|
||||
strPlayerBust db "ÏÅÐÅÁÎÐ (>21)! ÏÐÎÈÃÐÛØ",0
|
||||
|
||||
sym7 db " 777 ",0
|
||||
symBar db " BAR ",0
|
||||
symBell db " BELL",0
|
||||
symCherry db "CHERRY",0
|
||||
symClover db "CLOVER",0
|
||||
symGem db " GEM ",0
|
||||
symCrown db "CROWN",0
|
||||
symBell db 32,199,194,206,205,0
|
||||
symCherry db 194,200,216,205,223,0
|
||||
symClover db 202,203,197,194,197,208,0
|
||||
symGem db 192,203,204,192,199,0
|
||||
symCrown db 202,206,208,206,205,192,0
|
||||
|
||||
cardRankStr db "A ",0,"2 ",0,"3 ",0,"4 ",0,"5 ",0,"6 ",0,"7 ",0,"8 ",0,"9 ",0,"10",0,"J ",0,"Q ",0,"K ",0
|
||||
|
||||
|
|
@ -2647,14 +2651,15 @@ DrawDetailedCoin ENDP
|
|||
; IN-ENGINE 2.5D MINI-GAME: COIN FLIP
|
||||
; ==============================================================================
|
||||
InitCoinGame PROC
|
||||
mov coin3d_state, 0
|
||||
mov coin3d_timer, 0
|
||||
mov coin3d_streak, 0
|
||||
mov coin3d_win, 0
|
||||
call InitNativeCoin3D
|
||||
ret
|
||||
InitCoinGame ENDP
|
||||
|
||||
HandleCoinInput PROC
|
||||
call HandleNativeCoin3D
|
||||
ret
|
||||
; Retained legacy frame-count prototype, excluded from the executable.
|
||||
IF 0
|
||||
cmp coin3d_state, 0
|
||||
je coin_handle_idle
|
||||
cmp coin3d_state, 1
|
||||
|
|
@ -2775,6 +2780,7 @@ coin_handle_result:
|
|||
invoke PlayCasinoSound3D, OFFSET soundClick, 0, 1
|
||||
coin_done:
|
||||
ret
|
||||
ENDIF
|
||||
HandleCoinInput ENDP
|
||||
|
||||
RenderCoinGame PROC uses ebx esi edi
|
||||
|
|
@ -2782,6 +2788,9 @@ RenderCoinGame PROC uses ebx esi edi
|
|||
local rxVal:DWORD
|
||||
local kx:DWORD
|
||||
|
||||
call RenderNativeCoin3D
|
||||
ret
|
||||
IF 0
|
||||
; Background & Cabinet border
|
||||
invoke DrawBox, 0, 0, 320, 240, 00140906h
|
||||
invoke DrawBoxBorder, 6, 6, 308, 228, 0022150Fh, 00482E1Bh, 3
|
||||
|
|
@ -2894,6 +2903,7 @@ coin_render_keys:
|
|||
|
||||
invoke DrawKeycap3D, kx, 192, OFFSET textKeyEsc, 0
|
||||
ret
|
||||
ENDIF
|
||||
RenderCoinGame ENDP
|
||||
|
||||
; ==============================================================================
|
||||
|
|
@ -4693,7 +4703,10 @@ check_target_durak:
|
|||
check_target_slots777:
|
||||
cmp eax, INTERACT_SLOTS_777
|
||||
jne check_target_slots_clover
|
||||
call BeginUnavailable3D
|
||||
call InitNativeSlots3D
|
||||
test eax,eax
|
||||
jz target_unported
|
||||
mov engineMode,MODE_SLOTS
|
||||
ret
|
||||
|
||||
check_target_slots_clover:
|
||||
|
|
@ -5100,6 +5113,8 @@ include src_graphics\card_tables_render.inc
|
|||
include src_graphics\durak_render.inc
|
||||
include src_graphics\card_table_input.inc
|
||||
include src_graphics\scene_animation.inc
|
||||
include src_graphics\native_slots.inc
|
||||
include src_graphics\native_coin.inc
|
||||
include src_graphics\graphic_profiles.inc
|
||||
include src_graphics\city_arrival_scene.inc
|
||||
include src_graphics\arrival_scene.inc
|
||||
|
|
@ -5246,8 +5261,10 @@ check_slots_mode:
|
|||
@@:
|
||||
cmp engineMode, MODE_SLOTS
|
||||
jne check_bj_mode
|
||||
call HandleSlotsInput
|
||||
call RenderSlotsGame
|
||||
call HandleNativeSlots3D
|
||||
cmp engineMode,MODE_WALK
|
||||
je check_walk_mode
|
||||
call RenderNativeSlots3D
|
||||
jmp present_frame
|
||||
check_bj_mode:
|
||||
cmp engineMode, MODE_BLACKJACK
|
||||
|
|
@ -5355,7 +5372,7 @@ pause_draw_quality_value:
|
|||
invoke DrawString8x8, 44, 112, OFFSET textVolumeKeys3D, 00D8BC6Ah
|
||||
invoke DrawString8x8, 44, 130, OFFSET textSoundLevel3D, 00BBBBBBh
|
||||
invoke FormatNumber, settingsVolume, OFFSET hudNumBuffer
|
||||
invoke DrawString8x8, 108, 130, OFFSET hudNumBuffer, 00FFFFFFh
|
||||
invoke DrawString8x8, 124, 130, OFFSET hudNumBuffer, 00FFFFFFh
|
||||
invoke DrawString8x8, 44, 150, OFFSET textFullscreenKey3D, 00A0A0A0h
|
||||
invoke DrawString8x8, 44, 170, OFFSET textResume3D, 00D8BC6Ah
|
||||
invoke DrawString8x8, 44, 188, OFFSET textQuit3D, 00BBBBBBh
|
||||
|
|
@ -5441,6 +5458,7 @@ engine_shutdown:
|
|||
call FreeStartupAssets3D
|
||||
call FreeCardTableAssets3D
|
||||
call FreeBuckshotAssets3D
|
||||
call FreeNativeSlots3D
|
||||
call FreeArrivalAssets3D
|
||||
cmp h3DDC, 0
|
||||
je @F
|
||||
|
|
|
|||
BIN
dist/Assembler Casino.exe
vendored
|
|
@ -101,6 +101,28 @@ not decorative extra opponents. Native talisman effects, achievements, daily
|
|||
tasks and online tables still require integration with the selected profile.
|
||||
The old installer has not been repackaged with this work.
|
||||
|
||||
The classic 777 cabinet is now playable natively: generated cabinet/symbol art,
|
||||
three easing reel strips, sequential stops, selectable stakes, a paytable and
|
||||
queued safe exit. See `native-slots.md`. CloverPit remains a separate unported
|
||||
game rather than a renamed copy of this machine.
|
||||
|
||||
Hall furniture now uses isolated, tightly bounded table and cabinet packs rather
|
||||
than contaminated atlas cells. A full-height skill cabinet and twelve collidable
|
||||
lounge/rope props are described in `hall-furniture.md`; game entry IDs and saves
|
||||
remain unchanged.
|
||||
|
||||
European roulette now has matching first-person table/close-up scenes and a
|
||||
separately animated exact 37-pocket rotor, plus persistent result and queued exit.
|
||||
See `native-european-roulette.md` for supported bets and current visual limits.
|
||||
The six exterior walkers now exclusively use outdoor art and validated routes;
|
||||
street people/guards and hall tables use smaller world dimensions.
|
||||
|
||||
Coin toss now has its own first-person table, two embossed face sprites and
|
||||
sixteen hand poses with an integrated coin on the thumb before release.
|
||||
Its time-based toss, rotation, shadow and landing
|
||||
bounces end on the paid result, which stays visible until the next-round command.
|
||||
Escape queues a safe departure during the toss. See `native-coin-scene.md`.
|
||||
|
||||
The target is more than twenty actual games, not twenty menu placeholders. Native
|
||||
expansion candidates, to be specified and tested individually: Texas Hold'em,
|
||||
blackjack, Durak, European roulette, craps, coin toss, cups, Russian roulette,
|
||||
|
|
@ -119,6 +141,15 @@ Durak regressions include 500 complete games, all 5184 trump/attack/defense
|
|||
combinations, exact 36-card conservation, transfer/refill/take restrictions,
|
||||
all-card paging and exit from every active phase. A shared 52-card fill check
|
||||
guards against face-up cards incorrectly reading the back-color palette.
|
||||
777 checks cover all 8000 stop combinations, 500 complete spins at four update
|
||||
rates, monotonic reel paths, one-time debits/payouts and safe exit. Eight real
|
||||
native framebuffer snapshots check reel clipping and sequential stops.
|
||||
Hall furniture checks cover floor anchors, valid map cells, collision and the
|
||||
main passage, with three additional close-up native snapshots.
|
||||
Coin regressions cover 500 paid flips at four update rates, every exit phase,
|
||||
1701 continuous coin positions, wager controls, missing-art rejection and ten
|
||||
native framebuffer captures. `check_coin_scene.py --parity` also compares the
|
||||
tested coin procedures with the shipping object.
|
||||
The camera route is sampled against the exterior map, the full timed opening
|
||||
must reach profile selection, restarting must return to the black transition,
|
||||
and renderer calls must restore the hall camera, eye height, map, horizon, floor,
|
||||
|
|
|
|||
29
docs/coin-detail-window.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# Coin Result Window
|
||||
|
||||
The native MASM coin scene opens an owned, non-activating graphical window to
|
||||
the right of the main game. It renders into a separate 320 x 400 BGRA buffer,
|
||||
using the same coin faces, toss clock and actual outcome as the table scene.
|
||||
It does not choose another outcome or change wagers, payouts or RNG state.
|
||||
|
||||
The outcome remains hidden until the coin lands. The window then shows the
|
||||
actual face, a large Russian side label, win/loss and the net stake change.
|
||||
The result stays until the player requests another toss. The window closes
|
||||
when leaving the game, including an exit queued during an unfinished toss.
|
||||
Closing its X only closes the preview; the main scene's view button reopens it.
|
||||
|
||||
In fullscreen, a temporary strip is reserved on the right. Closing the preview
|
||||
restores the previous main-window rectangle. F11 restores the temporary layout
|
||||
before changing fullscreen mode and then reopens the preview. A subsequent
|
||||
explicit window move is not overwritten by preview cleanup. Placement uses the
|
||||
owning monitor's work area, including negative multi-monitor coordinates.
|
||||
|
||||
Russian UI labels are stored in `assets/data/ui-ru.json` as an offline authoring
|
||||
map. `tools/generators/compile_ui_ru.py` compiles only the listed declarations
|
||||
to decimal CP1251 bytes in assembly. No JSON or non-assembly runtime is added.
|
||||
Brand logos, standard card ranks and literal keyboard key names remain intact.
|
||||
|
||||
Verification includes hidden native owner/preview creation, repeat opening,
|
||||
monitor bounds, restoration, F11 and absence of a quit message from preview
|
||||
closure. Native captures verify both outcome faces and actual Cyrillic glyphs.
|
||||
The detail renderer is checked not to overwrite the main scene or alter bank
|
||||
and RNG state. The existing 500-flip coin tests cover settlement and safe exits.
|
||||
37
docs/hall-furniture.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# Hall Furniture V5
|
||||
|
||||
The runtime remains MASM32 assembly. Python only packs art and verifies native
|
||||
framebuffer captures offline; no Python dependency is shipped with the game.
|
||||
|
||||
## Corrections
|
||||
|
||||
- Card, roulette and backroom tables use their own tightly bounded ANM1 packs,
|
||||
rather than equal atlas-grid cells containing pieces of adjacent dancers.
|
||||
- Slot cabinets also use isolated complete frames, including the upper housing.
|
||||
- Skill checks use a dedicated tall cabinet with a timing dial, hook, button
|
||||
pedestal and floor base. Its world height is independent of table height.
|
||||
- Table dimensions now cover the full table and its legs, not transparent sheet
|
||||
margins. Dedicated assets retain a zero-height floor anchor.
|
||||
- Twelve decor objects form three seating groups and three rope boundaries.
|
||||
They have collision footprints and stay clear of the existing patron route,
|
||||
bar serving side, stairs and game approaches.
|
||||
- Missing dedicated art is not replaced with the old contaminated atlas frame.
|
||||
Existing station interaction IDs, game rules and saved data are unchanged.
|
||||
|
||||
## Assets
|
||||
|
||||
New art: `assets/sprites/hall/furniture-v5.png`.
|
||||
Built-in image_gen prompt: `assets/sprites/hall/prompts-v5.json`.
|
||||
Existing source art: `assets/sprites/casino-atlas-v1.png`.
|
||||
Packed runtime assets: `assets/animations/hall/*-v5.bin`.
|
||||
Packing: `tools/generators/pack_hall_furniture.py`.
|
||||
|
||||
## Verification
|
||||
|
||||
`tools/tests/hall_furniture_test.inc` validates station binding, cabinet
|
||||
dimensions, floor anchors, collision, map occupancy and the main passage.
|
||||
It captures the actual MASM renderer at table, skill cabinet and lounge views.
|
||||
The full native action suite also checks visitor routes and old scene/game rules.
|
||||
|
||||
`tools/tests/check_hall_furniture.py --parity` validates alpha/bounds, captures
|
||||
and COFF function parity between the tested and published assembly builds.
|
||||
45
docs/native-coin-scene.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Native coin table
|
||||
|
||||
Coin toss now stays inside the graphical MASM executable. Its first-person
|
||||
table, two readable coin faces and sixteen hand poses are separate packed assets.
|
||||
The dealer is a static background character, not an animated rig.
|
||||
|
||||
## Controls and settlement
|
||||
|
||||
- Choose heads/tails with the buttons or 1/2.
|
||||
- Change the stake with +/- buttons or W/S and Up/Down (50 through 5000).
|
||||
- Start with TOSS, Space or Enter. The stake is debited once at this point.
|
||||
- A winning flip returns twice the stake, including the original stake.
|
||||
- The result stays visible until AGAIN, Space or Enter returns to selection.
|
||||
- EXIT or Escape during a paid toss queues departure until settlement.
|
||||
- Missing art blocks paid play, and insufficient funds never reduce the stake automatically.
|
||||
|
||||
Progress is saved through the existing native profile path on debit and settlement.
|
||||
This is the current local save model, not a crash-recovery journal for unfinished bets.
|
||||
|
||||
## Animation
|
||||
|
||||
The 1700 ms timeline has a 300 ms thumb preparation, a 720 ms ballistic flight,
|
||||
two small landing bounces and a final resting pose. In the first five poses the
|
||||
coin and supporting fingers are one sprite, aligned to the launch point (414,266).
|
||||
There is no separate, floating coin layer before release. Airborne rotation has
|
||||
constant angular speed, rather than slowing into a hover. Rotation ends on the
|
||||
actual chosen result. Position, face, squash, withdrawal and shadow are derived from
|
||||
elapsed milliseconds rather than frame counts. Rendering does not consume RNG
|
||||
or alter the wager/outcome. This is an authored toss animation, not rigid-body physics.
|
||||
|
||||
## Assets and checks
|
||||
|
||||
Source images and complete built-in image-generation prompts:
|
||||
`assets/sprites/coin/{table,faces}-v1.png`, `hands-v2.png`,
|
||||
`prompts-v1.json` and `prompts-v2.json`.
|
||||
The offline Python packer is `tools/generators/pack_coin_assets.py`;
|
||||
the game loads only ANM1 packs from `assets/animations/coin/`.
|
||||
No Python or C/C++ runtime was added.
|
||||
|
||||
Native assertions live in `tools/tests/coin_test.inc` and run inside the real
|
||||
assembly action-test executable. The checker `tools/tests/check_coin_scene.py`
|
||||
validates assets and captured framebuffers, with optional tested/shipping COFF parity.
|
||||
The launch-path asset probe also loads these packs from the root and from an
|
||||
unrelated working directory. Run those checks after building; this document does
|
||||
not itself certify a particular build.
|
||||
57
docs/native-european-roulette.md
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# Native European roulette
|
||||
|
||||
The graphical roulette table stays inside the MASM game window. It uses a
|
||||
generated first-person felt/table view and a matching close-up of the same bowl.
|
||||
The 37-pocket rotor is a separate precision asset, inverse-sampled and
|
||||
projected onto the bowl ellipse by assembly code. Upright screen-space numerals
|
||||
are drawn separately in MASM so the perspective never squashes or rotates their
|
||||
glyphs. Close-up labels use a crisp 3x5 font at 2x scale; the distant betting
|
||||
view uses 1x scale. A settled pocket has a gold outline and its result is also
|
||||
displayed in the wheel centre. Frame timing, counter-rotating
|
||||
ball motion, camera transition, betting, input and payouts are also assembly.
|
||||
Python only packs art and validates offline fixtures; it is not the runtime.
|
||||
|
||||
## Betting and rounds
|
||||
|
||||
Click a number, including the single zero, or an outside bet. The felt's top,
|
||||
middle and bottom rows are 3/2/1. Supported bets are straight numbers, red/black,
|
||||
even/odd, 1-18/19-36, three dozens and three columns. Split, street, corner and
|
||||
six-line bets are not implemented. Gross multipliers are 36, 2 and 3 respectively;
|
||||
zero loses every outside bet. Chip size is $50 to $1,000,000, adjustable with the
|
||||
plus/minus controls or W/S. Clear/Backspace resets a draft without charging it.
|
||||
Spin/Space charges the complete stake once and starts a 4.2-second spin.
|
||||
|
||||
The winning number is not printed during the spin. The rotor and ball slow down,
|
||||
the ball moves into the selected pocket, and result/payout stay on screen until
|
||||
BETS, Space or Enter returns to a fresh betting layout. Results cannot be
|
||||
charged or settled again by repeated updates. Escape/EXIT leaves a draft/result
|
||||
immediately; during a spin it queues departure until settlement. Missing art
|
||||
blocks a paid spin and never opens a console fallback.
|
||||
|
||||
## Assets and checks
|
||||
|
||||
- Generated sources: `assets/sprites/wheel/{table,closeup}-v1.png`.
|
||||
- Built-in image generation/edit prompts: `assets/sprites/wheel/prompts-v1.json`.
|
||||
- ANM1 packs: `assets/animations/wheel/{table,closeup}-v1.bin` and `rotor-v2.bin`.
|
||||
- Offline packer: `tools/generators/pack_european_wheel.py`.
|
||||
- Native assertions: `tools/tests/wheel_scene_test.inc`, called by the action suite.
|
||||
- Asset/frame/shipping checks: `tools/tests/check_european_wheel.py --parity`.
|
||||
|
||||
Native assertions exercise all 37 results with all 49 supported bets, one-time
|
||||
settlement, every numbered cell's input mapping, monotonic millisecond easing,
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
## Exterior scale fixes
|
||||
|
||||
Two former stationary indoor-guest sprites near the entrance now use outdoor
|
||||
walking frames and independent curb routes. All six walkers use reduced world
|
||||
dimensions; entrance guards are smaller too. Routes are sampled against the
|
||||
actual exterior map and must remain in empty cells. Indoor guest art is forbidden
|
||||
in the city prop registry. Existing hall tables are about eleven percent smaller;
|
||||
cabinet dimensions, station IDs and saved progress are unchanged.
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# Native scene fixes
|
||||
|
||||
The MASM game stays in one graphical window. Unported 777, CloverPit,
|
||||
The MASM game stays in one graphical window. Unported CloverPit,
|
||||
online roulette, Umamusume, tower, terminal and observer interactions open a
|
||||
native "not implemented yet" panel. Escape, E, Enter, Space or its close button
|
||||
return to the same position. Opening/closing never charges a stake, runs a
|
||||
|
|
@ -10,6 +10,8 @@ graphical interactions.
|
|||
|
||||
Durak now has a native animated table instead of that panel, including
|
||||
podkidnoy/perevodnoy rules and exit confirmation. See `native-durak.md`.
|
||||
777 now has an animated native cabinet, paytable and safely queued exit.
|
||||
See `native-slots.md`.
|
||||
|
||||
Russian roulette now renders the same first-person room/table style as
|
||||
Buckshot, with its own revolver/loading hands and independent asset buffers.
|
||||
|
|
|
|||
64
docs/native-slots.md
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# Native 777
|
||||
|
||||
The 777 cabinet in the hall now opens a playable first-person graphical slot
|
||||
machine, rather than the unavailable panel or a console routine. Runtime rules,
|
||||
input, reel movement, sprite clipping and bank settlement are MASM only.
|
||||
|
||||
## Rules
|
||||
|
||||
There is one paying line: the middle symbol on each of three independent drums.
|
||||
Each drum has 20 stops, with these symbol counts: cherries 5, lemon 4, grapes 3,
|
||||
bell 3, BAR 2, seven 1, diamond 1 and crown 1. Stops are sampled once when the
|
||||
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
|
||||
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
|
||||
remains 1000000000. Stakes are saved immediately and outcomes are settled and
|
||||
saved once. An insufficient bankroll never starts a paid spin.
|
||||
|
||||
## Interaction
|
||||
|
||||
Space/Enter and the spin button start one spin; W/S, arrow keys or the minus/plus
|
||||
buttons change the stake between spins. P or the payouts button opens a separate
|
||||
paytable. Escape first closes that overlay without leaving the machine.
|
||||
|
||||
During a spin, Escape or the header exit button queues a return to the same hall
|
||||
position after all three drums stop and the payout is saved. It does not pause,
|
||||
refund, forfeit a valid result, or allow another stake to be queued. Closing the
|
||||
application before settlement retains the already deducted stake; resumable
|
||||
pending rounds are not implemented.
|
||||
|
||||
## Art And Timing
|
||||
|
||||
The cabinet and eight symbol sprites were generated with the built-in image_gen
|
||||
tool in the existing detailed retro pixel-art direction. Source assets and exact
|
||||
prompts are in `assets/sprites/slots/`; the project does not depend on the tool's
|
||||
external image cache. `pack_slot_assets.py` normalizes them offline to one
|
||||
opaque 640x480 cabinet and eight alpha-tested 64x64 symbols in ANM1 packs.
|
||||
|
||||
Reels move through their complete strips with a monotonic quadratic ease-out,
|
||||
stopping at 1800, 2400 and 3000 milliseconds. Icons are clipped to each reel's
|
||||
window; neighboring cabinet artwork cannot be overwritten. The opaque cabinet
|
||||
uses a direct framebuffer copy rather than alpha sampling every background pixel.
|
||||
No pre-rendered spin video, C game implementation or frame-dependent RNG is used.
|
||||
|
||||
## Verification
|
||||
|
||||
`test_casino_actions.ps1 -SkipPreview` includes 8000 stop combinations, 500
|
||||
complete spins at four update rates, millisecond-by-millisecond monotonicity,
|
||||
idempotent payout, maximum-bank handling, missing/malformed assets, insufficient
|
||||
stakes, paytable and queued exit checks. Test saves remain disabled in the
|
||||
native test build. `check_slot_frames.py` checks eight real MASM framebuffer
|
||||
snapshots, sequential stops and symbol clipping. `check_slot_build.py` compares
|
||||
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.
|
||||
BIN
poker.exe
BIN
poker.obj
|
|
@ -18,4 +18,4 @@ DebOut=
|
|||
[FILES]
|
||||
1=poker.asm
|
||||
[SHOWFILE]
|
||||
1=0000000000000000140600007403000000000000030000000000000094
|
||||
1=0000000000000000140600007403000000000000030000004836000012
|
||||
|
|
|
|||
|
|
@ -42,20 +42,20 @@ entryDisplayName3D db 24 dup(0)
|
|||
entryDat3D db ".dat",0
|
||||
entryWildcard3D db "\*.dat",0
|
||||
entryLocalRoot3D db ".",0
|
||||
entryWelcome3D db "CASINO / ENTRY",0
|
||||
entryChoose3D db "YOUR PROFILE",0
|
||||
entryGuest3D db "PREVIEW PROFILE",0
|
||||
entryNew3D db "+ NEW PLAYER",0
|
||||
entryNameText3D db "PLAYER NAME",0
|
||||
entryWelcome3D db 194,213,206,196,32,194,32,202,192,199,200,205,206,0
|
||||
entryChoose3D db 194,192,216,32,207,208,206,212,200,203,220,0
|
||||
entryGuest3D db 195,206,209,210,220,0
|
||||
entryNew3D db 43,32,205,206,194,219,201,32,200,195,208,206,202,0
|
||||
entryNameText3D db 200,204,223,32,200,195,208,206,202,192,0
|
||||
entryNameHint3D db "A-Z 0-9 _ -",0
|
||||
entryConfirm3D db "ENTER",0
|
||||
entryCancel3D db "ESC: BACK",0
|
||||
entryContinue3D db "WELCOME",0
|
||||
entryConfirm3D db 194,206,201,210,200,0
|
||||
entryCancel3D db 69,83,67,58,32,205,192,199,192,196,0
|
||||
entryContinue3D db 196,206,193,208,206,32,207,206,198,192,203,206,194,192,210,220,0
|
||||
entryMoney3D db "$",0
|
||||
entryProfileError3D db "CANNOT LOAD SAVE",0
|
||||
entryNameError3D db "NAME TAKEN / I/O",0
|
||||
entryStop3D db "ONE MOMENT.",0
|
||||
entryChecking3D db "CHECKING THE GUEST LIST",0
|
||||
entryReady3D db "PLEASE, COME IN.",0
|
||||
entrySkip3D db "ENTER: APPROACH",0
|
||||
entryProfileError3D db 209,193,206,201,32,199,192,195,208,211,199,202,200,0
|
||||
entryNameError3D db 200,204,223,32,199,192,205,223,210,206,32,47,32,209,193,206,201,0
|
||||
entryStop3D db 206,196,205,211,32,204,200,205,211,210,211,46,0
|
||||
entryChecking3D db 207,208,206,194,197,208,223,197,204,32,209,207,200,209,206,202,32,195,206,209,210,197,201,0
|
||||
entryReady3D db 207,208,206,213,206,196,200,210,197,46,0
|
||||
entrySkip3D db 69,78,84,69,82,58,32,207,206,196,206,201,210,200,0
|
||||
.code
|
||||
|
|
|
|||
|
|
@ -47,20 +47,20 @@ poolCharge3D dd 0
|
|||
poolAccumulator3D dd 0
|
||||
poolTime3D dd 0
|
||||
poolStill3D dd 0
|
||||
poolTitle3D db "8 BALL",0
|
||||
poolPlayerText3D db "PLAYER",0
|
||||
poolDealerText3D db "DEALER",0
|
||||
poolOpenText3D db "OPEN TABLE",0
|
||||
poolSolidsText3D db "SOLIDS",0
|
||||
poolStripesText3D db "STRIPES",0
|
||||
poolFoulText3D db "FOUL / BALL IN HAND",0
|
||||
poolWinText3D db "RACK WON",0
|
||||
poolShotText3D db "SHOT",0
|
||||
poolRackText3D db "RERACK",0
|
||||
poolPowerText3D db "POWER",0
|
||||
poolPlaceText3D db "PLACE CUE BALL",0
|
||||
poolMovingText3D db "ROLLING",0
|
||||
poolBallText3D db "BALL",0
|
||||
poolPocketText3D db "POCKET",0
|
||||
poolTitle3D db 207,211,203,32,47,32,56,0
|
||||
poolPlayerText3D db 200,195,208,206,202,0
|
||||
poolDealerText3D db 196,200,203,197,208,0
|
||||
poolOpenText3D db 209,210,206,203,32,206,210,202,208,219,210,0
|
||||
poolSolidsText3D db 209,207,203,206,216,205,219,197,0
|
||||
poolStripesText3D db 207,206,203,206,209,192,210,219,197,0
|
||||
poolFoulText3D db 212,206,203,32,47,32,209,32,208,211,202,200,0
|
||||
poolWinText3D db 207,206,193,197,196,192,0
|
||||
poolShotText3D db 211,196,192,208,0
|
||||
poolRackText3D db 199,192,205,206,194,206,0
|
||||
poolPowerText3D db 209,200,203,192,0
|
||||
poolPlaceText3D db 207,206,209,210,192,194,220,210,197,32,193,200,210,206,202,0
|
||||
poolMovingText3D db 202,192,210,223,210,209,223,0
|
||||
poolBallText3D db 216,192,208,0
|
||||
poolPocketText3D db 203,211,199,192,0
|
||||
poolGroupTexts3D dd OFFSET poolOpenText3D,OFFSET poolSolidsText3D,OFFSET poolStripesText3D
|
||||
.code
|
||||
|
|
|
|||
|
|
@ -1283,9 +1283,9 @@ bs_draw_health:
|
|||
sub eax, bs3d_shellIndex
|
||||
invoke DrawBuckshotNumber3D, 78, 396, eax, 00FFFFFFh
|
||||
invoke DrawBuckshotText3D, 14, 412, OFFSET bs3d_textLive, 00DF6656h
|
||||
invoke DrawBuckshotNumber3D, 52, 412, bs3d_liveCount, 00DF6656h
|
||||
invoke DrawBuckshotText3D, 76, 412, OFFSET bs3d_textBlank, 007DBBCCh
|
||||
invoke DrawBuckshotNumber3D, 120, 412, bs3d_blankCount, 007DBBCCh
|
||||
invoke DrawBuckshotNumber3D, 70, 412, bs3d_liveCount, 00DF6656h
|
||||
invoke DrawBuckshotText3D, 14, 430, OFFSET bs3d_textBlank, 007DBBCCh
|
||||
invoke DrawBuckshotNumber3D, 86, 430, bs3d_blankCount, 007DBBCCh
|
||||
xor esi, esi
|
||||
bs_draw_inventory:
|
||||
imul ebx, esi, 112
|
||||
|
|
@ -1345,9 +1345,9 @@ bs_draw_ready:
|
|||
invoke DrawBuckshotPanel3D, 112, 416, 28, 22, 00404A46h
|
||||
invoke DrawBuckshotText3D, 122, 423, OFFSET bs3d_plus, 00FFFFFFh
|
||||
invoke DrawBuckshotText3D, 22, 451, OFFSET bs3d_textBet, 00C7B88Fh
|
||||
invoke DrawBuckshotNumber3D, 64, 451, bs3d_bet, 00FFFFFFh
|
||||
invoke DrawBuckshotNumber3D, 92, 451, bs3d_bet, 00FFFFFFh
|
||||
invoke DrawBuckshotPanel3D, 246, 446, 136, 24, 00363C30h
|
||||
invoke DrawBuckshotText3D, 270, 454, OFFSET bs3d_textReady, 00E1C67Bh
|
||||
invoke DrawBuckshotText3D, 258, 454, OFFSET bs3d_textReady, 00E1C67Bh
|
||||
invoke DrawBuckshotText3D, 548, 454, OFFSET bs3d_textExit, 00AFAFAFh
|
||||
cmp bs3d_error, 0
|
||||
je bs_draw_done
|
||||
|
|
@ -1363,13 +1363,13 @@ bs_draw_player:
|
|||
jmp bs_draw_notice
|
||||
bs_draw_win:
|
||||
invoke DrawBuckshotText3D, 20, 455, OFFSET bs3d_textWin, 007FE395h
|
||||
invoke DrawBuckshotNumber3D, 96, 455, bs3d_payout, 007FE395h
|
||||
invoke DrawBuckshotNumber3D, 120, 455, bs3d_payout, 007FE395h
|
||||
jmp bs_draw_result
|
||||
bs_draw_lose:
|
||||
invoke DrawBuckshotText3D, 20, 455, OFFSET bs3d_textLose, 00E1766Ah
|
||||
bs_draw_result:
|
||||
invoke DrawBuckshotPanel3D, 246, 446, 136, 24, 00363C30h
|
||||
invoke DrawBuckshotText3D, 266, 455, OFFSET bs3d_textResult, 00E1C67Bh
|
||||
invoke DrawBuckshotText3D, 254, 455, OFFSET bs3d_textResult, 00E1C67Bh
|
||||
invoke DrawBuckshotText3D, 548, 455, OFFSET bs3d_textExit, 00AFAFAFh
|
||||
jmp bs_draw_done
|
||||
bs_draw_notice:
|
||||
|
|
|
|||
|
|
@ -99,42 +99,43 @@ bs3d_frameCounts dd 1,12,16,16,12,8,8,12,32,8,16,8
|
|||
bs3d_frameWidths dd 640,320,320,256,128,256,320,256,384,320,256,128
|
||||
bs3d_frameHeights dd 480,280,280,224,128,256,280,224,256,240,224,128
|
||||
bs3d_pumpSound db "assets\audio\generated\buckshot-pump.wav",0
|
||||
bs3d_textTitle db "BUCKSHOT",0
|
||||
bs3d_textBank db "BANK $",0
|
||||
bs3d_textPlayer db "PLAYER",0
|
||||
bs3d_textDealer db "DEALER",0
|
||||
bs3d_textBet db "BET $",0
|
||||
bs3d_textReady db "SPACE: PLAY",0
|
||||
bs3d_textResult db "SPACE: AGAIN",0
|
||||
bs3d_textExit db "ESC: HALL",0
|
||||
bs3d_textPause db "ESC: PAUSE",0
|
||||
bs3d_textChoose db "1: SELF",0
|
||||
bs3d_textOpponent db "2: DEALER",0
|
||||
bs3d_textWin db "YOU WIN",0
|
||||
bs3d_textLose db "DEALER WINS",0
|
||||
bs3d_textLoad db "RELOADING",0
|
||||
bs3d_textLive db "LIVE",0
|
||||
bs3d_textBlank db "BLANK",0
|
||||
bs3d_textShells db "SHELLS",0
|
||||
bs3d_textEmpty db "NOT ENOUGH CASH",0
|
||||
bs3d_textShot db "LIVE ROUND",0
|
||||
bs3d_textDry db "BLANK ROUND",0
|
||||
bs3d_textKnownLive db "NEXT: LIVE",0
|
||||
bs3d_textKnownBlank db "NEXT: BLANK",0
|
||||
bs3d_textSaw db "NEXT DAMAGE x2",0
|
||||
bs3d_textBeer db "SHELL EJECTED",0
|
||||
bs3d_textCuffs db "OPPONENT SKIPS A TURN",0
|
||||
bs3d_textItemEmpty db "ITEM UNAVAILABLE",0
|
||||
bs3d_textWait db "DEALER'S TURN",0
|
||||
bs3d_textItem db "USING AN ITEM",0
|
||||
bs3d_textAssets db "ANIMATION FILE MISSING OR INVALID",0
|
||||
bs3d_textMedical db "MEDICAL UNIT: RESTORING VITALS",0
|
||||
bs3d_textDeath db "VITAL SIGNAL LOST",0
|
||||
bs3d_textTitle db 193,192,202,216,206,210,0
|
||||
bs3d_textBank db 193,192,205,202,32,36,0
|
||||
bs3d_textPlayer db 200,195,208,206,202,0
|
||||
bs3d_textDealer db 196,200,203,197,208,0
|
||||
bs3d_textBet db 209,210,192,194,202,192,32,36,0
|
||||
bs3d_textReady db 207,208,206,193,197,203,58,32,200,195,208,192,210,220,0
|
||||
bs3d_textResult db 207,208,206,193,197,203,58,32,197,217,168,32,208,192,199,0
|
||||
bs3d_textExit db 69,83,67,58,32,213,206,203,203,0
|
||||
bs3d_textPause db 69,83,67,58,32,207,192,211,199,192,0
|
||||
bs3d_textChoose db 49,58,32,194,32,209,197,193,223,0
|
||||
bs3d_textOpponent db 50,58,32,194,32,196,200,203,197,208,192,0
|
||||
bs3d_textWin db 194,219,32,194,219,200,195,208,192,203,200,0
|
||||
bs3d_textLose db 196,200,203,197,208,32,194,219,200,195,208,192,203,0
|
||||
bs3d_textLoad db 207,197,208,197,199,192,208,223,196,202,192,0
|
||||
bs3d_textLive db 193,206,197,194,219,197,0
|
||||
bs3d_textBlank db 213,206,203,206,209,210,219,197,0
|
||||
bs3d_textShells db 207,192,210,208,206,205,219,0
|
||||
bs3d_textEmpty db 204,192,203,206,32,196,197,205,197,195,0
|
||||
bs3d_textShot db 193,206,197,194,206,201,32,207,192,210,208,206,205,0
|
||||
bs3d_textDry db 213,206,203,206,209,210,206,201,32,207,192,210,208,206,205,0
|
||||
bs3d_textKnownLive db 209,203,197,196,211,222,217,200,201,58,32,193,206,197,194,206,201,0
|
||||
bs3d_textKnownBlank db 209,203,197,196,211,222,217,200,201,58,32,213,206,203,206,209,210,206,201,0
|
||||
bs3d_textSaw db 211,208,206,205,32,209,203,197,196,211,222,217,197,195,206,32,194,219,209,210,208,197,203,192,32,120,50,0
|
||||
bs3d_textBeer db 207,192,210,208,206,205,32,194,219,193,208,206,216,197,205,0
|
||||
bs3d_textCuffs db 207,208,206,210,200,194,205,200,202,32,207,208,206,207,211,209,202,192,197,210,32,213,206,196,0
|
||||
bs3d_textItemEmpty db 207,208,197,196,204,197,210,32,205,197,196,206,209,210,211,207,197,205,0
|
||||
bs3d_textWait db 213,206,196,32,196,200,203,197,208,192,0
|
||||
bs3d_textItem db 200,209,207,206,203,220,199,211,197,204,32,207,208,197,196,204,197,210,0
|
||||
bs3d_textAssets db 192,205,200,204,192,214,200,223,32,205,197,32,205,192,201,196,197,205,192,32,200,203,200,32,207,206,194,208,197,198,196,197
|
||||
db 205,192,0
|
||||
bs3d_textMedical db 204,197,196,200,214,200,205,209,202,192,223,32,204,192,216,200,205,192,58,32,208,197,192,205,200,204,192,214,200,223,0
|
||||
bs3d_textDeath db 198,200,199,205,197,205,205,219,201,32,209,200,195,205,192,203,32,207,206,210,197,208,223,205,0
|
||||
bs3d_textItems dd OFFSET bs3d_textGlassKey,OFFSET bs3d_textSawKey
|
||||
dd OFFSET bs3d_textBeerKey,OFFSET bs3d_textCuffKey
|
||||
bs3d_textGlassKey db "3: GLASS",0
|
||||
bs3d_textSawKey db "4: SAW",0
|
||||
bs3d_textBeerKey db "5: BEER",0
|
||||
bs3d_textCuffKey db "6: CUFFS",0
|
||||
bs3d_textGlassKey db 51,58,32,203,211,207,192,0
|
||||
bs3d_textSawKey db 52,58,32,207,200,203,192,0
|
||||
bs3d_textBeerKey db 53,58,32,207,200,194,206,0
|
||||
bs3d_textCuffKey db 54,58,206,202,206,194,219,0
|
||||
bs3d_minus db "-",0
|
||||
bs3d_plus db "+",0
|
||||
|
|
|
|||
|
|
@ -146,6 +146,24 @@ RequestCardExit3D ENDP
|
|||
|
||||
; Called by the engine's Escape dispatch, before the generic pause branch.
|
||||
CardTableEscape3D PROC
|
||||
cmp engineMode, MODE_COIN
|
||||
jne @F
|
||||
call CoinEscape3D
|
||||
mov eax,1
|
||||
ret
|
||||
@@:
|
||||
cmp engineMode, MODE_ROULETTE
|
||||
jne @F
|
||||
call WheelEscape3D
|
||||
mov eax,1
|
||||
ret
|
||||
@@:
|
||||
cmp engineMode, MODE_SLOTS
|
||||
jne @F
|
||||
call SlotEscape3D
|
||||
mov eax,1
|
||||
ret
|
||||
@@:
|
||||
cmp engineMode, MODE_POKER
|
||||
je card_escape_handle
|
||||
cmp engineMode, MODE_BLACKJACK
|
||||
|
|
|
|||
|
|
@ -108,41 +108,41 @@ pkError3D dd 0
|
|||
pkChipActor3D dd 0
|
||||
pkChipAmount3D dd 0
|
||||
pkChipTimer3D dd 320
|
||||
pkTitle3D db "TEXAS HOLD'EM",0
|
||||
pkPotText3D db "POT $",0
|
||||
pkStreet0Text3D db "PREFLOP",0
|
||||
pkStreet1Text3D db "FLOP",0
|
||||
pkStreet2Text3D db "TURN",0
|
||||
pkStreet3Text3D db "RIVER",0
|
||||
pkTitle3D db 210,197,213,192,209,209,202,200,201,32,213,206,203,196,197,204,0
|
||||
pkPotText3D db 193,192,205,202,0
|
||||
pkStreet0Text3D db 207,208,197,212,203,206,207,0
|
||||
pkStreet1Text3D db 212,203,206,207,0
|
||||
pkStreet2Text3D db 210,168,208,205,0
|
||||
pkStreet3Text3D db 208,200,194,197,208,0
|
||||
pkStreetNames3D dd OFFSET pkStreet0Text3D,OFFSET pkStreet1Text3D,OFFSET pkStreet2Text3D,OFFSET pkStreet3Text3D
|
||||
pkCheckText3D db "CHECK",0
|
||||
pkCallText3D db "CALL",0
|
||||
pkRaiseText3D db "RAISE",0
|
||||
pkFoldText3D db "FOLD",0
|
||||
pkAllInText3D db "ALL-IN",0
|
||||
pkCostText3D db "CALL $",0
|
||||
pkMinimumText3D db "MIN RAISE",0
|
||||
pkDealText3D db "DEAL",0
|
||||
pkNextText3D db "NEXT",0
|
||||
pkAiWait3D db "DEALER",0
|
||||
pkAiCheck3D db "CHECK",0
|
||||
pkAiCall3D db "CALL",0
|
||||
pkAiRaise3D db "RAISE",0
|
||||
pkAiFold3D db "FOLD",0
|
||||
pkCheckText3D db 207,192,209,0
|
||||
pkCallText3D db 211,208,192,194,205,223,210,220,0
|
||||
pkRaiseText3D db 207,206,194,219,209,200,210,220,0
|
||||
pkFoldText3D db 209,193,208,206,209,0
|
||||
pkAllInText3D db 194,192,45,193,192,205,202,0
|
||||
pkCostText3D db 202,206,203,203,0
|
||||
pkMinimumText3D db 204,200,205,46,32,208,197,201,199,0
|
||||
pkDealText3D db 209,196,192,210,220,0
|
||||
pkNextText3D db 196,192,203,197,197,0
|
||||
pkAiWait3D db 196,200,203,197,208,0
|
||||
pkAiCheck3D db 207,192,209,0
|
||||
pkAiCall3D db 202,206,203,203,0
|
||||
pkAiRaise3D db 208,197,201,199,0
|
||||
pkAiFold3D db 209,193,208,206,209,0
|
||||
pkAiNames3D dd OFFSET pkAiWait3D,OFFSET pkAiCheck3D,OFFSET pkAiCall3D,OFFSET pkAiRaise3D,OFFSET pkAiFold3D
|
||||
pkWinText3D db "YOU WIN",0
|
||||
pkLoseText3D db "DEALER WINS",0
|
||||
pkTieText3D db "SPLIT POT",0
|
||||
pkWinText3D db 194,219,32,194,219,200,195,208,192,203,200,0
|
||||
pkLoseText3D db 196,200,203,197,208,32,194,219,200,195,208,192,203,0
|
||||
pkTieText3D db 193,192,205,202,32,207,206,208,206,194,205,211,0
|
||||
pkResults3D dd OFFSET pkWinText3D,OFFSET pkLoseText3D,OFFSET pkTieText3D
|
||||
pkRank0 db "HIGH CARD",0
|
||||
pkRank1 db "PAIR",0
|
||||
pkRank2 db "TWO PAIR",0
|
||||
pkRank3 db "THREE OF A KIND",0
|
||||
pkRank4 db "STRAIGHT",0
|
||||
pkRank5 db "FLUSH",0
|
||||
pkRank6 db "FULL HOUSE",0
|
||||
pkRank7 db "FOUR OF A KIND",0
|
||||
pkRank8 db "STRAIGHT FLUSH",0
|
||||
pkRank0 db 209,210,192,208,216,192,223,32,202,192,208,210,192,0
|
||||
pkRank1 db 207,192,208,192,0
|
||||
pkRank2 db 196,194,197,32,207,192,208,219,0
|
||||
pkRank3 db 210,208,206,201,202,192,0
|
||||
pkRank4 db 209,210,208,200,210,0
|
||||
pkRank5 db 212,203,197,216,0
|
||||
pkRank6 db 212,211,203,203,45,213,192,211,209,0
|
||||
pkRank7 db 202,192,208,197,0
|
||||
pkRank8 db 209,210,208,200,210,45,212,203,197,216,0
|
||||
pkRankNames3D dd OFFSET pkRank0,OFFSET pkRank1,OFFSET pkRank2,OFFSET pkRank3,OFFSET pkRank4
|
||||
dd OFFSET pkRank5,OFFSET pkRank6,OFFSET pkRank7,OFFSET pkRank8
|
||||
pkRankLimits3D dd 7462,6185,3325,2467,1609,1599,322,166,10
|
||||
|
|
@ -163,15 +163,15 @@ cbDouble3D dd 0
|
|||
cbOutcome3D dd 0
|
||||
cbCard3D dd 0
|
||||
cbError3D dd 0
|
||||
cbTitle3D db "BLACKJACK / 21",0
|
||||
cbHitText3D db "HIT",0
|
||||
cbStandText3D db "STAND",0
|
||||
cbDoubleText3D db "DOUBLE",0
|
||||
cbNaturalText3D db "BLACKJACK",0
|
||||
cbTitle3D db 193,203,221,202,196,198,197,202,32,47,32,50,49,0
|
||||
cbHitText3D db 202,192,208,210,192,0
|
||||
cbStandText3D db 213,194,192,210,200,210,0
|
||||
cbDoubleText3D db 211,196,194,206,200,210,220,0
|
||||
cbNaturalText3D db 193,203,221,202,196,198,197,202,0
|
||||
cbResults3D dd OFFSET pkWinText3D,OFFSET pkLoseText3D,OFFSET textTie3D
|
||||
tableBlindText3D db "BLIND $",0
|
||||
tableRaiseText3D db "RAISE +$",0
|
||||
tableScoreText3D db "TOTAL",0
|
||||
tableBlindText3D db 193,203,192,201,205,196,32,36,0
|
||||
tableRaiseText3D db 208,197,201,199,32,43,36,0
|
||||
tableScoreText3D db 206,215,202,200,0
|
||||
tablePlusText3D db "+",0
|
||||
tableMinusText3D db "-",0
|
||||
tableDealOrder3D dd 0,2,1,3
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ bj_render_stake_enabled:
|
|||
invoke DrawStakeControls3D, eax
|
||||
invoke DrawString8x8, 8, 36, OFFSET textBet3D, 00DDCFB1h
|
||||
invoke FormatNumber, cbBet3D, OFFSET hudNumBuffer
|
||||
invoke DrawString8x8, 48, 36, OFFSET hudNumBuffer, 00F6F4DDh
|
||||
invoke DrawString8x8, 80, 36, OFFSET hudNumBuffer, 00F6F4DDh
|
||||
cmp cbState3D, CB_IDLE
|
||||
je bj_render_buttons
|
||||
xor edi, edi
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ CITY_PROP_COUNT equ 47
|
|||
CITY_FIRST_CAR equ 9
|
||||
CITY_TRAFFIC_EAST equ 14
|
||||
CITY_TRAFFIC_WEST equ 15
|
||||
CITY_PEDESTRIAN_COUNT equ 4
|
||||
CITY_PEDESTRIAN_COUNT equ 6
|
||||
CityWalkRoute3D STRUCT
|
||||
objectIndex dd ?
|
||||
minX dd ?
|
||||
|
|
@ -109,9 +109,9 @@ cityObjects3D CityProp3D <(8*FP_1+FP_1/3),(26*FP_1+FP_1/3),FP_1*3/2,FP_1*5/4,0,O
|
|||
CityProp3D <4*FP_1,14*FP_1,FP_1*3,FP_1*9/5,8,OFFSET cityCarsPack3D>
|
||||
CityProp3D <28*FP_1,15*FP_1+FP_1/5,FP_1*3,FP_1*9/5,0,OFFSET cityCarsPack3D>
|
||||
cityNearMan3D LABEL BYTE
|
||||
CityProp3D <12*FP_1,FP_1*253/20,FP_1,FP_1*9/5,0,OFFSET hallStreetLife3D>
|
||||
CityProp3D <12*FP_1,FP_1*253/20,FP_1*7/10,FP_1*27/20,0,OFFSET hallStreetLife3D>
|
||||
cityFarWoman3D LABEL BYTE
|
||||
CityProp3D <26*FP_1,FP_1*169/10,FP_1*6/5,2*FP_1,16,OFFSET hallStreetLife3D>
|
||||
CityProp3D <26*FP_1,FP_1*169/10,FP_1*4/5,FP_1*7/5,16,OFFSET hallStreetLife3D>
|
||||
CityProp3D <26*FP_1,FP_1*259/20,FP_1*4/5,FP_1,34,OFFSET hallStreetLife3D>
|
||||
CityProp3D <10*FP_1+FP_HALF,FP_1*333/20,FP_1*4/5,FP_1*6/5,35,OFFSET hallStreetLife3D>
|
||||
CityProp3D <21*FP_1,FP_1*259/20,FP_1/4,FP_1*23/50,36,OFFSET hallStreetLife3D>
|
||||
|
|
@ -119,9 +119,9 @@ cityFarWoman3D LABEL BYTE
|
|||
CityProp3D <34*FP_1,FP_1*259/20,FP_1,3*FP_1,3,OFFSET cityPropsPack3D>
|
||||
; Another walking pair occupies the near and far curbs, not the traffic lanes.
|
||||
cityNearWoman3D LABEL BYTE
|
||||
CityProp3D <14*FP_1,FP_1*63/5,FP_1*6/5,2*FP_1,16,OFFSET hallStreetLife3D>
|
||||
CityProp3D <14*FP_1,FP_1*63/5,FP_1*4/5,FP_1*7/5,16,OFFSET hallStreetLife3D>
|
||||
cityFarMan3D LABEL BYTE
|
||||
CityProp3D <22*FP_1,FP_1*337/20,FP_1,FP_1*9/5,0,OFFSET hallStreetLife3D>
|
||||
CityProp3D <22*FP_1,FP_1*337/20,FP_1*7/10,FP_1*27/20,0,OFFSET hallStreetLife3D>
|
||||
; Near-side street furniture is staggered along the route and clear of its center.
|
||||
CityProp3D <12*FP_1,FP_1*259/20,FP_1*3/5,FP_1/2,33,OFFSET hallStreetLife3D>
|
||||
CityProp3D <14*FP_1+FP_HALF,FP_1*259/20,FP_1*4/5,FP_1*6/5,35,OFFSET hallStreetLife3D>
|
||||
|
|
@ -129,9 +129,11 @@ cityFarMan3D LABEL BYTE
|
|||
CityProp3D <16*FP_1,FP_1*259/20,FP_1/4,FP_1*23/50,36,OFFSET hallStreetLife3D>
|
||||
CityProp3D <18*FP_1,FP_1*259/20,FP_1/4,FP_1*23/50,36,OFFSET hallStreetLife3D>
|
||||
CityProp3D <24*FP_1,FP_1*259/20,FP_1/4,FP_1*23/50,36,OFFSET hallStreetLife3D>
|
||||
; Waiting guests flank the entrance instead of blocking it.
|
||||
CityProp3D <20*FP_1+FP_HALF,9*FP_1,FP_1*17/20,FP_1*17/10,1,OFFSET hallPatrons3D>
|
||||
CityProp3D <24*FP_1+FP_HALF,9*FP_1,FP_1*17/20,FP_1*17/10,5,OFFSET hallPatrons3D>
|
||||
; Independent outdoor walkers replace the stationary indoor visitor billboards.
|
||||
cityEntryMan3D LABEL BYTE
|
||||
CityProp3D <20*FP_1+FP_HALF,9*FP_1,FP_1*7/10,FP_1*27/20,0,OFFSET hallStreetLife3D>
|
||||
cityEntryWoman3D LABEL BYTE
|
||||
CityProp3D <24*FP_1+FP_HALF,9*FP_1,FP_1*4/5,FP_1*7/5,16,OFFSET hallStreetLife3D>
|
||||
CityProp3D <13*FP_1,FP_1*333/20,FP_1*4/5,FP_1,34,OFFSET hallStreetLife3D>
|
||||
CityProp3D <21*FP_1,FP_1*333/20,FP_1*4/5,FP_1*6/5,35,OFFSET hallStreetLife3D>
|
||||
CityProp3D <24*FP_1,FP_1*333/20,FP_1,3*FP_1,3,OFFSET cityPropsPack3D>
|
||||
|
|
@ -153,6 +155,8 @@ cityWalkRoutes3D CityWalkRoute3D <(cityNearMan3D-cityObjects3D)/SIZEOF CityProp3
|
|||
CityWalkRoute3D <(cityFarWoman3D-cityObjects3D)/SIZEOF CityProp3D,10*FP_1,28*FP_1,FP_1*169/10,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>
|
||||
IFDEF CASINO_ACTION_TEST
|
||||
cityVisiblePixels3D dd CITY_PROP_COUNT dup(0)
|
||||
ENDIF
|
||||
|
|
|
|||
438
src_graphics/coin_detail.inc
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
; An owned, non-activating window shares the game's clock and settled outcome.
|
||||
OpenCoinDetail3D PROC
|
||||
cmp h3DWnd,0
|
||||
je detail_open_done
|
||||
cmp coinDetailWnd3D,0
|
||||
jne detail_open_done
|
||||
mov coinDetailWC3D.cbSize,SIZEOF C3D_WNDCLASSEX
|
||||
mov coinDetailWC3D.style,CS_HREDRAW or CS_VREDRAW
|
||||
mov coinDetailWC3D.lpfnWndProc,OFFSET CoinDetailEvents3D
|
||||
mov eax,h3DInst
|
||||
mov coinDetailWC3D.hInstance,eax
|
||||
mov coinDetailWC3D.lpszClassName,OFFSET coinDetailClass3D
|
||||
invoke LoadCursorA,0,32512
|
||||
mov coinDetailWC3D.hCursor,eax
|
||||
invoke RegisterClassExA,OFFSET coinDetailWC3D
|
||||
mov coinDetailBmi3D.bmiHeader.biSize,SIZEOF C3D_BITMAPINFOHEADER
|
||||
mov coinDetailBmi3D.bmiHeader.biWidth,COIN_DETAIL_W
|
||||
mov coinDetailBmi3D.bmiHeader.biHeight,-COIN_DETAIL_H
|
||||
mov coinDetailBmi3D.bmiHeader.biPlanes,1
|
||||
mov coinDetailBmi3D.bmiHeader.biBitCount,32
|
||||
mov coinDetailBmi3D.bmiHeader.biSizeImage,COIN_DETAIL_W*COIN_DETAIL_H*4
|
||||
invoke CreateWindowExA,08000080h,OFFSET coinDetailClass3D,OFFSET coinDetailTitle3D,80800000h,0,0,COIN_DETAIL_W,COIN_DETAIL_H,h3DWnd,0,h3DInst,0
|
||||
mov coinDetailWnd3D,eax
|
||||
test eax,eax
|
||||
jz detail_open_done
|
||||
call LayoutCoinDetail3D
|
||||
invoke IsWindowVisible,h3DWnd
|
||||
test eax,eax
|
||||
jz detail_open_done
|
||||
invoke ShowWindow,coinDetailWnd3D,4
|
||||
detail_open_done:
|
||||
ret
|
||||
OpenCoinDetail3D ENDP
|
||||
|
||||
; Restore only our own resize; never overwrite a later F11 or user window move.
|
||||
CloseCoinDetail3D PROC uses esi edi
|
||||
local current:CoinDetailRect3D
|
||||
cmp coinDetailWnd3D,0
|
||||
je detail_restore
|
||||
invoke DestroyWindow,coinDetailWnd3D
|
||||
mov coinDetailWnd3D,0
|
||||
detail_restore:
|
||||
cmp coinDetailReserved3D,0
|
||||
je detail_close_done
|
||||
mov coinDetailReserved3D,0
|
||||
invoke IsWindow,h3DWnd
|
||||
test eax,eax
|
||||
jz detail_close_done
|
||||
mov eax,fullscreen3D
|
||||
cmp eax,coinDetailFullscreen3D
|
||||
jne detail_close_done
|
||||
invoke GetWindowRect,h3DWnd,ADDR current
|
||||
lea esi,current
|
||||
lea edi,coinDetailApplied3D
|
||||
mov ecx,4
|
||||
repe cmpsd
|
||||
jne detail_close_done
|
||||
mov eax,coinDetailOriginal3D[8]
|
||||
sub eax,coinDetailOriginal3D
|
||||
mov edx,coinDetailOriginal3D[12]
|
||||
sub edx,coinDetailOriginal3D[4]
|
||||
invoke SetWindowPos,h3DWnd,0,coinDetailOriginal3D,coinDetailOriginal3D[4],eax,edx,14h
|
||||
detail_close_done:
|
||||
ret
|
||||
CloseCoinDetail3D ENDP
|
||||
|
||||
LayoutCoinDetail3D PROC uses ebx esi edi
|
||||
local current:CoinDetailRect3D,panelX:DWORD,panelY:DWORD,panelW:DWORD,panelH:DWORD
|
||||
cmp coinDetailWnd3D,0
|
||||
je detail_layout_done
|
||||
mov eax,coinDetailWidth3D
|
||||
mov panelW,eax
|
||||
mov eax,coinDetailHeight3D
|
||||
mov panelH,eax
|
||||
invoke GetWindowRect,h3DWnd,ADDR current
|
||||
cmp coinDetailReserved3D,0
|
||||
je detail_layout_new
|
||||
mov eax,fullscreen3D
|
||||
cmp eax,coinDetailFullscreen3D
|
||||
jne detail_layout_new
|
||||
lea esi,current
|
||||
lea edi,coinDetailApplied3D
|
||||
mov ecx,4
|
||||
repe cmpsd
|
||||
je detail_layout_position
|
||||
detail_layout_new:
|
||||
mov coinDetailReserved3D,0
|
||||
invoke MonitorFromWindow,h3DWnd,2
|
||||
invoke GetMonitorInfoA,eax,OFFSET coinDetailMonitor3D
|
||||
test eax,eax
|
||||
jz detail_layout_done
|
||||
; Work area bounds include taskbar and monitors with a negative origin.
|
||||
mov ebx,coinDetailMonitor3D[28]
|
||||
sub ebx,coinDetailMonitor3D[20]
|
||||
mov eax,COIN_DETAIL_W
|
||||
cmp ebx,800
|
||||
jae @F
|
||||
mov eax,ebx
|
||||
shr eax,2
|
||||
@@:
|
||||
mov panelW,eax
|
||||
mov eax,coinDetailMonitor3D[32]
|
||||
sub eax,coinDetailMonitor3D[24]
|
||||
cmp eax,COIN_DETAIL_H
|
||||
jbe @F
|
||||
mov eax,COIN_DETAIL_H
|
||||
@@:
|
||||
mov panelH,eax
|
||||
mov coinDetailHeight3D,eax
|
||||
mov eax,panelW
|
||||
mov coinDetailWidth3D,eax
|
||||
mov eax,current.right
|
||||
add eax,8
|
||||
add eax,panelW
|
||||
cmp eax,coinDetailMonitor3D[28]
|
||||
jle detail_layout_position
|
||||
lea esi,current
|
||||
lea edi,coinDetailOriginal3D
|
||||
mov ecx,4
|
||||
rep movsd
|
||||
mov eax,fullscreen3D
|
||||
mov coinDetailFullscreen3D,eax
|
||||
mov eax,coinDetailMonitor3D[28]
|
||||
sub eax,panelW
|
||||
sub eax,8
|
||||
sub eax,coinDetailMonitor3D[20]
|
||||
mov ebx,coinDetailMonitor3D[32]
|
||||
sub ebx,coinDetailMonitor3D[24]
|
||||
invoke SetWindowPos,h3DWnd,0,coinDetailMonitor3D[20],coinDetailMonitor3D[24],eax,ebx,14h
|
||||
invoke GetWindowRect,h3DWnd,ADDR current
|
||||
lea esi,current
|
||||
lea edi,coinDetailApplied3D
|
||||
mov ecx,4
|
||||
rep movsd
|
||||
mov coinDetailReserved3D,1
|
||||
detail_layout_position:
|
||||
mov eax,current.right
|
||||
add eax,8
|
||||
mov panelX,eax
|
||||
mov eax,current.top
|
||||
mov ebx,current.bottom
|
||||
sub ebx,eax
|
||||
sub ebx,panelH
|
||||
sar ebx,1
|
||||
add eax,ebx
|
||||
cmp eax,coinDetailMonitor3D[24]
|
||||
jge @F
|
||||
mov eax,coinDetailMonitor3D[24]
|
||||
@@:
|
||||
mov ebx,coinDetailMonitor3D[32]
|
||||
sub ebx,panelH
|
||||
cmp eax,ebx
|
||||
jle @F
|
||||
mov eax,ebx
|
||||
@@:
|
||||
mov panelY,eax
|
||||
invoke SetWindowPos,coinDetailWnd3D,0,panelX,panelY,panelW,panelH,14h
|
||||
detail_layout_done:
|
||||
ret
|
||||
LayoutCoinDetail3D ENDP
|
||||
|
||||
UpdateCoinDetail3D PROC
|
||||
cmp coinDetailWnd3D,0
|
||||
je detail_update_done
|
||||
call LayoutCoinDetail3D
|
||||
invoke InvalidateRect,coinDetailWnd3D,0,0
|
||||
invoke UpdateWindow,coinDetailWnd3D
|
||||
detail_update_done:
|
||||
ret
|
||||
UpdateCoinDetail3D ENDP
|
||||
|
||||
CoinDetailEvents3D PROC hwnd:DWORD,message:DWORD,wp:DWORD,lp:DWORD
|
||||
local paint:CoinDetailPaint3D,rect:CoinDetailRect3D,dc:DWORD
|
||||
cmp message,WM_CLOSE
|
||||
je detail_event_close
|
||||
cmp message,WM_DESTROY
|
||||
je detail_event_destroy
|
||||
cmp message,201h
|
||||
jne @F
|
||||
invoke GetClientRect,hwnd,ADDR rect
|
||||
movzx eax,WORD PTR lp
|
||||
imul eax,COIN_DETAIL_W
|
||||
xor edx,edx
|
||||
div rect.right
|
||||
cmp eax,280
|
||||
jb detail_event_done
|
||||
movzx eax,WORD PTR lp[2]
|
||||
imul eax,COIN_DETAIL_H
|
||||
xor edx,edx
|
||||
div rect.bottom
|
||||
cmp eax,36
|
||||
jb detail_event_close
|
||||
jmp detail_event_done
|
||||
@@:
|
||||
cmp message,14h
|
||||
jne @F
|
||||
mov eax,1
|
||||
ret
|
||||
@@:
|
||||
cmp message,21h
|
||||
jne @F
|
||||
mov eax,3
|
||||
ret
|
||||
@@:
|
||||
cmp message,0Fh
|
||||
jne detail_event_default
|
||||
invoke BeginPaint,hwnd,ADDR paint
|
||||
mov dc,eax
|
||||
call RenderCoinDetail3D
|
||||
invoke GetClientRect,hwnd,ADDR rect
|
||||
invoke StretchDIBits,dc,0,0,rect.right,rect.bottom,0,0,COIN_DETAIL_W,COIN_DETAIL_H,OFFSET coinDetailBuffer3D,OFFSET coinDetailBmi3D,0,SRCCOPY
|
||||
invoke EndPaint,hwnd,ADDR paint
|
||||
jmp detail_event_done
|
||||
detail_event_close:
|
||||
call CloseCoinDetail3D
|
||||
jmp detail_event_done
|
||||
detail_event_destroy:
|
||||
mov coinDetailWnd3D,0
|
||||
detail_event_done:
|
||||
xor eax,eax
|
||||
ret
|
||||
detail_event_default:
|
||||
invoke DefWindowProcA,hwnd,message,wp,lp
|
||||
ret
|
||||
CoinDetailEvents3D ENDP
|
||||
|
||||
CoinDetailBox3D PROC uses edi x:DWORD,y:DWORD,w:DWORD,h:DWORD,color:DWORD
|
||||
local row:DWORD
|
||||
mov eax,y
|
||||
mov row,eax
|
||||
detail_box_row:
|
||||
mov eax,row
|
||||
cmp eax,COIN_DETAIL_H
|
||||
jae detail_box_done
|
||||
imul eax,COIN_DETAIL_W
|
||||
add eax,x
|
||||
lea edi,coinDetailBuffer3D[eax*4]
|
||||
mov ecx,w
|
||||
mov eax,color
|
||||
rep stosd
|
||||
inc row
|
||||
dec h
|
||||
jnz detail_box_row
|
||||
detail_box_done:
|
||||
ret
|
||||
CoinDetailBox3D ENDP
|
||||
|
||||
CoinDetailText3D PROC uses ebx esi edi x:DWORD,y:DWORD,pText:DWORD,color:DWORD,scale:DWORD
|
||||
local row:DWORD,column:DWORD,bits:DWORD
|
||||
mov esi,pText
|
||||
detail_text_char:
|
||||
movzx eax,BYTE PTR [esi]
|
||||
test eax,eax
|
||||
jz detail_text_done
|
||||
lea ebx,font8x8[eax*8]
|
||||
mov row,0
|
||||
detail_text_row:
|
||||
mov ecx,row
|
||||
movzx eax,BYTE PTR [ebx+ecx]
|
||||
mov bits,eax
|
||||
mov column,0
|
||||
detail_text_pixel:
|
||||
test bits,80h
|
||||
jz detail_text_next
|
||||
mov eax,column
|
||||
imul eax,scale
|
||||
add eax,x
|
||||
mov edx,scale
|
||||
add edx,eax
|
||||
cmp edx,COIN_DETAIL_W
|
||||
ja detail_text_next
|
||||
mov edx,row
|
||||
imul edx,scale
|
||||
add edx,y
|
||||
mov ecx,scale
|
||||
add ecx,edx
|
||||
cmp ecx,COIN_DETAIL_H
|
||||
ja detail_text_next
|
||||
invoke CoinDetailBox3D,eax,edx,scale,scale,color
|
||||
detail_text_next:
|
||||
shl bits,1
|
||||
inc column
|
||||
cmp column,8
|
||||
jb detail_text_pixel
|
||||
inc row
|
||||
cmp row,8
|
||||
jb detail_text_row
|
||||
mov eax,scale
|
||||
shl eax,3
|
||||
add x,eax
|
||||
inc esi
|
||||
jmp detail_text_char
|
||||
detail_text_done:
|
||||
ret
|
||||
CoinDetailText3D ENDP
|
||||
|
||||
CoinDetailNumber3D PROC uses ebx edi x:DWORD,y:DWORD,value:DWORD,color:DWORD
|
||||
local digits[16]:BYTE
|
||||
lea edi,digits[15]
|
||||
mov BYTE PTR [edi],0
|
||||
mov eax,value
|
||||
mov ebx,10
|
||||
detail_number_digit:
|
||||
xor edx,edx
|
||||
div ebx
|
||||
add dl,'0'
|
||||
dec edi
|
||||
mov [edi],dl
|
||||
test eax,eax
|
||||
jnz detail_number_digit
|
||||
invoke CoinDetailText3D,x,y,edi,color,2
|
||||
ret
|
||||
CoinDetailNumber3D ENDP
|
||||
|
||||
; Binary-alpha faces are sampled into a private buffer, never the main scene.
|
||||
CoinDetailFace3D PROC uses ebx esi edi face:DWORD,height:DWORD
|
||||
local row:DWORD,column:DWORD,sourceRow:DWORD,top:DWORD
|
||||
cmp coinFacesArt3D.pixels,0
|
||||
je detail_face_done
|
||||
mov eax,face
|
||||
and eax,1
|
||||
shl eax,16
|
||||
add eax,coinFacesArt3D.pixels
|
||||
mov esi,eax
|
||||
mov eax,height
|
||||
shr eax,1
|
||||
neg eax
|
||||
add eax,166
|
||||
mov top,eax
|
||||
mov row,0
|
||||
detail_face_row:
|
||||
mov eax,row
|
||||
shl eax,7
|
||||
xor edx,edx
|
||||
div height
|
||||
shl eax,9
|
||||
mov sourceRow,eax
|
||||
mov eax,row
|
||||
add eax,top
|
||||
imul eax,COIN_DETAIL_W
|
||||
add eax,60
|
||||
lea edi,coinDetailBuffer3D[eax*4]
|
||||
mov column,0
|
||||
detail_face_pixel:
|
||||
mov eax,column
|
||||
shl eax,7
|
||||
xor edx,edx
|
||||
mov ecx,200
|
||||
div ecx
|
||||
shl eax,2
|
||||
add eax,sourceRow
|
||||
mov ebx,[esi+eax]
|
||||
test ebx,0FF000000h
|
||||
jz @F
|
||||
mov [edi],ebx
|
||||
@@:
|
||||
add edi,4
|
||||
inc column
|
||||
cmp column,200
|
||||
jb detail_face_pixel
|
||||
inc row
|
||||
mov eax,row
|
||||
cmp eax,height
|
||||
jb detail_face_row
|
||||
detail_face_done:
|
||||
ret
|
||||
CoinDetailFace3D ENDP
|
||||
|
||||
RenderCoinDetail3D PROC uses ebx esi edi
|
||||
invoke CoinDetailBox3D,0,0,320,400,0014191Dh
|
||||
invoke CoinDetailBox3D,0,0,320,36,00252D2Ah
|
||||
invoke CoinDetailText3D,16,10,OFFSET coinDetailTitle3D,00E5D29Eh,2
|
||||
invoke CoinDetailText3D,292,10,OFFSET coinDetailClose3D,00ADB9BCh,2
|
||||
cmp coinArtReady3D,1
|
||||
jne detail_render_missing
|
||||
invoke CoinPose3D,coin3d_timer
|
||||
mov ebx,200
|
||||
cmp coin3d_state,COIN_IDLE
|
||||
je detail_render_face
|
||||
cmp coin3d_timer,COIN_LAND_MS
|
||||
jae detail_render_face
|
||||
mov eax,coinAngle3D
|
||||
mov ebx,tableCos[eax*4]
|
||||
test ebx,ebx
|
||||
jns @F
|
||||
neg ebx
|
||||
@@:
|
||||
imul ebx,200
|
||||
shr ebx,16
|
||||
cmp ebx,6
|
||||
jae detail_render_face
|
||||
mov ebx,6
|
||||
detail_render_face:
|
||||
invoke CoinDetailFace3D,coinFace3D,ebx
|
||||
cmp coin3d_state,COIN_IDLE
|
||||
je detail_render_pick
|
||||
cmp coin3d_timer,COIN_LAND_MS
|
||||
jb detail_render_air
|
||||
mov eax,OFFSET coinHeadsText3D
|
||||
mov ebx,96
|
||||
cmp coin3d_result,1
|
||||
je @F
|
||||
mov eax,OFFSET coinTailsText3D
|
||||
mov ebx,80
|
||||
@@:
|
||||
invoke CoinDetailText3D,ebx,284,eax,00F4E7C8h,4
|
||||
mov eax,coin3d_result
|
||||
cmp eax,coin3d_choice
|
||||
jne detail_render_loss
|
||||
invoke CoinDetailText3D,104,336,OFFSET coinDetailWin3D,0087D4A5h,2
|
||||
invoke CoinDetailText3D,100,366,OFFSET coinDetailPlus3D,0087D4A5h,2
|
||||
invoke CoinDetailNumber3D,124,366,coin3d_bet,0087D4A5h
|
||||
invoke CoinDetailText3D,212,366,OFFSET coinDetailCash3D,0087D4A5h,2
|
||||
ret
|
||||
detail_render_loss:
|
||||
invoke CoinDetailText3D,96,336,OFFSET coinDetailLose3D,00E99383h,2
|
||||
invoke CoinDetailText3D,100,366,OFFSET coinDetailMinus3D,00E99383h,2
|
||||
invoke CoinDetailNumber3D,124,366,coin3d_bet,00E99383h
|
||||
invoke CoinDetailText3D,212,366,OFFSET coinDetailCash3D,00E99383h,2
|
||||
ret
|
||||
detail_render_air:
|
||||
invoke CoinDetailText3D,40,310,OFFSET coinDetailAir3D,00E5D29Eh,2
|
||||
ret
|
||||
detail_render_pick:
|
||||
invoke CoinDetailText3D,104,292,OFFSET coinDetailPick3D,00ADB9BCh,2
|
||||
mov eax,OFFSET coinHeadsText3D
|
||||
mov ebx,96
|
||||
cmp coin3d_choice,1
|
||||
je @F
|
||||
mov eax,OFFSET coinTailsText3D
|
||||
mov ebx,80
|
||||
@@:
|
||||
invoke CoinDetailText3D,ebx,330,eax,00F4E7C8h,4
|
||||
ret
|
||||
detail_render_missing:
|
||||
invoke CoinDetailText3D,16,190,OFFSET coinMissingText3D,00E99383h,2
|
||||
ret
|
||||
RenderCoinDetail3D ENDP
|
||||
54
src_graphics/coin_detail_data.inc
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
COIN_DETAIL_W equ 320
|
||||
COIN_DETAIL_H equ 400
|
||||
IsWindow PROTO :DWORD
|
||||
IsWindowVisible PROTO :DWORD
|
||||
InvalidateRect PROTO :DWORD,:DWORD,:DWORD
|
||||
GetWindow PROTO :DWORD,:DWORD
|
||||
CoinDetailRect3D STRUCT
|
||||
left dd ?
|
||||
top dd ?
|
||||
right dd ?
|
||||
bottom dd ?
|
||||
CoinDetailRect3D ENDS
|
||||
CoinDetailPaint3D STRUCT
|
||||
dc dd ?
|
||||
erase dd ?
|
||||
rect CoinDetailRect3D <>
|
||||
restore dd ?
|
||||
update dd ?
|
||||
reserved db 32 dup(?)
|
||||
CoinDetailPaint3D ENDS
|
||||
OpenCoinDetail3D PROTO
|
||||
CloseCoinDetail3D PROTO
|
||||
LayoutCoinDetail3D PROTO
|
||||
UpdateCoinDetail3D PROTO
|
||||
RenderCoinDetail3D PROTO
|
||||
CoinDetailEvents3D PROTO :DWORD,:DWORD,:DWORD,:DWORD
|
||||
CoinDetailBox3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
CoinDetailText3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
CoinDetailFace3D PROTO :DWORD,:DWORD
|
||||
CoinDetailNumber3D PROTO :DWORD,:DWORD,:DWORD,:DWORD
|
||||
.data
|
||||
coinDetailClass3D db "CasinoCoinDetail",0
|
||||
coinDetailWnd3D dd 0
|
||||
coinDetailWC3D C3D_WNDCLASSEX <>
|
||||
coinDetailBmi3D C3D_BITMAPINFO <>
|
||||
coinDetailReserved3D dd 0
|
||||
coinDetailFullscreen3D dd 0
|
||||
coinDetailWidth3D dd 320
|
||||
coinDetailHeight3D dd 400
|
||||
coinDetailOriginal3D dd 4 dup(0)
|
||||
coinDetailApplied3D dd 4 dup(0)
|
||||
coinDetailMonitor3D dd 40,9 dup(0)
|
||||
coinDetailBuffer3D dd (COIN_DETAIL_W*COIN_DETAIL_H) dup(0)
|
||||
coinDetailView3D db 194,200,196,0
|
||||
coinDetailTitle3D db 204,206,205,197,210,192,0
|
||||
coinDetailClose3D db "X",0
|
||||
coinDetailAir3D db 204,206,205,197,210,192,32,194,32,207,206,203,168,210,197,0
|
||||
coinDetailPick3D db 194,219,193,208,192,205,206,0
|
||||
coinDetailWin3D db 194,219,200,195,208,219,216,0
|
||||
coinDetailLose3D db 207,208,206,200,195,208,219,216,0
|
||||
coinDetailPlus3D db "+",0
|
||||
coinDetailMinus3D db "-",0
|
||||
coinDetailCash3D db "$",0
|
||||
.code
|
||||
|
|
@ -79,8 +79,44 @@ hallPropsPath3D db "assets\animations\hall\props.bin",0
|
|||
hallDrinkPath3D db "assets\animations\hall\drink-v4.bin",0
|
||||
hallLegacyPack3D AnimPack3D <314D4E41h,128,128,1,128*128*4,0>
|
||||
hallSpriteTemp3D CityProp3D <>
|
||||
hallSpriteWidths3D dd 3 dup(FP_1*3/5),4 dup(FP_1*3/2),2 dup(FP_1),5 dup(FP_1*3/2),FP_1,FP_1,FP_1,5 dup(FP_1*3/2)
|
||||
hallSpriteHeights3D dd 3 dup(FP_1*6/5),4 dup(FP_1*4/5),2 dup(FP_1*3/2),5 dup(FP_1*4/5),FP_1,FP_1*3/2,FP_1*3/2,5 dup(FP_1*4/5)
|
||||
; Tight sprite bounds: table height includes its legs; cabinets are not table-sized.
|
||||
hallSpriteWidths3D dd 3 dup(FP_1*3/5),4 dup(FP_1*8/5),2 dup(FP_1),3 dup(FP_1*8/5),FP_1,FP_1*8/5,FP_1,FP_1,FP_1,5 dup(FP_1*8/5)
|
||||
hallSpriteHeights3D dd 3 dup(FP_1*6/5),4 dup(FP_1*17/20),2 dup(FP_1*3/2),3 dup(FP_1*17/20),FP_1*9/5,FP_1*17/20,FP_1,FP_1*3/2,FP_1*3/2,5 dup(FP_1*17/20)
|
||||
hallCardFurniture3D AnimPack3D <>
|
||||
hallWheelFurniture3D AnimPack3D <>
|
||||
hallBackFurniture3D AnimPack3D <>
|
||||
hallSkillFurniture3D AnimPack3D <>
|
||||
hallChairFurniture3D AnimPack3D <>
|
||||
hallLampFurniture3D AnimPack3D <>
|
||||
hallRopeFurniture3D AnimPack3D <>
|
||||
hallSlotFurniture3D AnimPack3D <>
|
||||
hallCardFurniturePath3D db "assets\animations\hall\card-table-v5.bin",0
|
||||
hallWheelFurniturePath3D db "assets\animations\hall\roulette-table-v5.bin",0
|
||||
hallBackFurniturePath3D db "assets\animations\hall\backroom-table-v5.bin",0
|
||||
hallSkillFurniturePath3D db "assets\animations\hall\skill-cabinet-v5.bin",0
|
||||
hallChairFurniturePath3D db "assets\animations\hall\lounge-chair-v5.bin",0
|
||||
hallLampFurniturePath3D db "assets\animations\hall\lamp-table-v5.bin",0
|
||||
hallRopeFurniturePath3D db "assets\animations\hall\velvet-rope-v5.bin",0
|
||||
hallSlotFurniturePath3D db "assets\animations\hall\slot-cabinets-v5.bin",0
|
||||
; Station order matches InitializeCasinoSprites3D; zero retains animated legacy art.
|
||||
hallStationPacks3D dd 3 dup(0),OFFSET hallCardFurniture3D,OFFSET hallWheelFurniture3D
|
||||
dd 2 dup(OFFSET hallCardFurniture3D),2 dup(OFFSET hallSlotFurniture3D)
|
||||
dd 3 dup(OFFSET hallCardFurniture3D),OFFSET hallSkillFurniture3D,OFFSET hallCardFurniture3D
|
||||
dd 3 dup(0),OFFSET hallBackFurniture3D,OFFSET hallCardFurniture3D
|
||||
dd 2 dup(OFFSET hallBackFurniture3D),0
|
||||
HALL_DECOR_COUNT equ 12
|
||||
hallLoungeDecor3D CityProp3D <13*FP_1,19*FP_1,FP_1*3/4,FP_1,0,OFFSET hallChairFurniture3D>
|
||||
CityProp3D <14*FP_1,19*FP_1,FP_1*3/5,FP_1*7/10,0,OFFSET hallLampFurniture3D>
|
||||
CityProp3D <15*FP_1,19*FP_1,FP_1*3/4,FP_1,0,OFFSET hallChairFurniture3D>
|
||||
CityProp3D <27*FP_1,18*FP_1,FP_1*3/4,FP_1,0,OFFSET hallChairFurniture3D>
|
||||
CityProp3D <28*FP_1,18*FP_1,FP_1*3/5,FP_1*7/10,0,OFFSET hallLampFurniture3D>
|
||||
CityProp3D <29*FP_1,18*FP_1,FP_1*3/4,FP_1,0,OFFSET hallChairFurniture3D>
|
||||
CityProp3D <3*FP_1,18*FP_1,FP_1*3/4,FP_1,0,OFFSET hallChairFurniture3D>
|
||||
CityProp3D <4*FP_1,18*FP_1,FP_1*3/5,FP_1*7/10,0,OFFSET hallLampFurniture3D>
|
||||
CityProp3D <5*FP_1,18*FP_1,FP_1*3/4,FP_1,0,OFFSET hallChairFurniture3D>
|
||||
CityProp3D <6*FP_1,6*FP_1,FP_1*9/5,FP_1*7/10,0,OFFSET hallRopeFurniture3D>
|
||||
CityProp3D <26*FP_1,6*FP_1,FP_1*9/5,FP_1*7/10,0,OFFSET hallRopeFurniture3D>
|
||||
CityProp3D <28*FP_1,22*FP_1,FP_1*9/5,FP_1*7/10,0,OFFSET hallRopeFurniture3D>
|
||||
HALL_PROP_COUNT equ 19
|
||||
hallObjects3D CityProp3D <12*FP_1+FP_HALF,7*FP_1,FP_1*3/5,FP_1*6/5,0,OFFSET hallProps3D>
|
||||
CityProp3D <16*FP_1+FP_HALF,9*FP_1,FP_1*3/5,FP_1*6/5,2,OFFSET hallProps3D>
|
||||
|
|
@ -103,19 +139,19 @@ hallObjects3D CityProp3D <12*FP_1+FP_HALF,7*FP_1,FP_1*3/5,FP_1*6/5,0,OFFSET hall
|
|||
CityProp3D <14*FP_1,14*FP_1,FP_1*3/5,FP_1*6/5,2,OFFSET hallProps3D>
|
||||
bunkerMerchant3D CityProp3D <16*FP_1,13*FP_1,FP_1*3/2,FP_1*6/5,0,OFFSET merchantPack3D,FP_1/8>
|
||||
bunkerDoor3D CityProp3D <16*FP_1,27*FP_1,FP_1*3/2,FP_1*7/5,5,OFFSET hallProps3D,FP_1>
|
||||
cityGuardLeft3D CityProp3D <21*FP_1+FP_1*4/5,8*FP_1+FP_HALF,FP_1,FP_1*8/5,0,OFFSET guardPack3D>
|
||||
cityGuardRight3D CityProp3D <23*FP_1+FP_1/5,8*FP_1+FP_HALF,FP_1,FP_1*8/5,0,OFFSET guardPack3D>
|
||||
hallBarPrompt3D db "E: COCKTAIL BAR",0
|
||||
hallBunkerPrompt3D db "E: BASEMENT / SHOP",0
|
||||
hallUpPrompt3D db "E: UPSTAIRS",0
|
||||
hallPoolPrompt3D db "E: BILLIARDS",0
|
||||
barName3D db "OLD TOWN BAR",0
|
||||
barDrinks3D db "1 HIGHBALL $100",0
|
||||
barDrinks23D db "2 COCKTAIL $200",0
|
||||
barDrinks33D db "3 WATER $0",0
|
||||
barPoor3D db "NOT ENOUGH CHIPS",0
|
||||
barMixText3D db "MIXING",0
|
||||
barDrinkText3D db "CHEERS",0
|
||||
cityGuardLeft3D CityProp3D <21*FP_1+FP_1*4/5,8*FP_1+FP_HALF,FP_1*17/20,FP_1*7/5,0,OFFSET guardPack3D>
|
||||
cityGuardRight3D CityProp3D <23*FP_1+FP_1/5,8*FP_1+FP_HALF,FP_1*17/20,FP_1*7/5,0,OFFSET guardPack3D>
|
||||
hallBarPrompt3D db 69,58,32,202,206,202,210,197,201,203,220,205,219,201,32,193,192,208,0
|
||||
hallBunkerPrompt3D db 69,58,32,207,206,196,194,192,203,32,47,32,204,192,195,192,199,200,205,0
|
||||
hallUpPrompt3D db 69,58,32,205,192,194,197,208,213,0
|
||||
hallPoolPrompt3D db 69,58,32,193,200,203,220,223,208,196,0
|
||||
barName3D db 193,192,208,32,209,210,192,208,206,195,206,32,195,206,208,206,196,192,0
|
||||
barDrinks3D db 49,32,213,192,201,193,206,203,32,36,49,48,48,0
|
||||
barDrinks23D db 50,32,202,206,202,210,197,201,203,220,32,36,50,48,48,0
|
||||
barDrinks33D db 51,32,194,206,196,192,32,36,48,0
|
||||
barPoor3D db 204,192,203,206,32,212,200,216,197,202,0
|
||||
barMixText3D db 209,204,197,216,200,194,192,197,204,0
|
||||
barDrinkText3D db 194,192,216,197,32,199,196,206,208,206,194,220,197,0
|
||||
barTime3D dd 0
|
||||
barPhase3D dd 0
|
||||
barSelection3D dd 0
|
||||
|
|
|
|||
|
|
@ -238,6 +238,25 @@ hall_sprite_loop:
|
|||
mov hallLegacyPack3D.pixels, edx
|
||||
mov hallSpriteTemp3D.frame, 0
|
||||
mov hallSpriteTemp3D.asset, OFFSET hallLegacyPack3D
|
||||
mov eax, hallStationPacks3D[esi*4]
|
||||
test eax, eax
|
||||
jz hall_sprite_draw
|
||||
; Missing dedicated art hides the station, never shows a contaminated atlas cell.
|
||||
cmp [eax].AnimPack3D.pixels, 0
|
||||
je hall_sprite_next
|
||||
mov hallSpriteTemp3D.asset, eax
|
||||
cmp eax, OFFSET hallSlotFurniture3D
|
||||
jne hall_sprite_draw
|
||||
mov eax, animationClock3D
|
||||
xor edx, edx
|
||||
mov ecx, 320
|
||||
div ecx
|
||||
add eax, esi
|
||||
xor edx, edx
|
||||
mov ecx, 3
|
||||
div ecx
|
||||
mov hallSpriteTemp3D.frame, edx
|
||||
hall_sprite_draw:
|
||||
invoke DrawCityObject3D, OFFSET hallSpriteTemp3D, 0
|
||||
hall_sprite_next:
|
||||
inc esi
|
||||
|
|
@ -263,6 +282,14 @@ InitHall3D PROC uses esi edi
|
|||
InitHall3D ENDP
|
||||
|
||||
LoadHallAssets3D PROC
|
||||
invoke LoadAnimPack3D, OFFSET hallCardFurniture3D, OFFSET hallCardFurniturePath3D
|
||||
invoke LoadAnimPack3D, OFFSET hallWheelFurniture3D, OFFSET hallWheelFurniturePath3D
|
||||
invoke LoadAnimPack3D, OFFSET hallBackFurniture3D, OFFSET hallBackFurniturePath3D
|
||||
invoke LoadAnimPack3D, OFFSET hallSkillFurniture3D, OFFSET hallSkillFurniturePath3D
|
||||
invoke LoadAnimPack3D, OFFSET hallChairFurniture3D, OFFSET hallChairFurniturePath3D
|
||||
invoke LoadAnimPack3D, OFFSET hallLampFurniture3D, OFFSET hallLampFurniturePath3D
|
||||
invoke LoadAnimPack3D, OFFSET hallRopeFurniture3D, OFFSET hallRopeFurniturePath3D
|
||||
invoke LoadAnimPack3D, OFFSET hallSlotFurniture3D, OFFSET hallSlotFurniturePath3D
|
||||
invoke LoadAnimPack3D, OFFSET hallBartender3D, OFFSET hallBartenderPath3D
|
||||
invoke LoadAnimPack3D, OFFSET hallProps3D, OFFSET hallPropsPath3D
|
||||
invoke LoadAnimPack3D, OFFSET hallDrink3D, OFFSET hallDrinkPath3D
|
||||
|
|
@ -324,6 +351,16 @@ hall_load_sign:
|
|||
LoadHallAssets3D ENDP
|
||||
|
||||
FreeHallAssets3D PROC
|
||||
call FreeNativeWheelArt3D
|
||||
call FreeNativeCoinArt3D
|
||||
invoke FreeAnimPack3D, OFFSET hallCardFurniture3D
|
||||
invoke FreeAnimPack3D, OFFSET hallWheelFurniture3D
|
||||
invoke FreeAnimPack3D, OFFSET hallBackFurniture3D
|
||||
invoke FreeAnimPack3D, OFFSET hallSkillFurniture3D
|
||||
invoke FreeAnimPack3D, OFFSET hallChairFurniture3D
|
||||
invoke FreeAnimPack3D, OFFSET hallLampFurniture3D
|
||||
invoke FreeAnimPack3D, OFFSET hallRopeFurniture3D
|
||||
invoke FreeAnimPack3D, OFFSET hallSlotFurniture3D
|
||||
invoke FreeAnimPack3D, OFFSET hallBartender3D
|
||||
invoke FreeAnimPack3D, OFFSET hallProps3D
|
||||
invoke FreeAnimPack3D, OFFSET hallDrink3D
|
||||
|
|
@ -485,6 +522,14 @@ hall_render_lights:
|
|||
inc esi
|
||||
cmp esi, HALL_LIGHT_COUNT
|
||||
jb hall_render_lights
|
||||
xor esi, esi
|
||||
hall_render_lounge:
|
||||
imul eax, esi, SIZEOF CityProp3D
|
||||
add eax, OFFSET hallLoungeDecor3D
|
||||
invoke DrawCityObject3D,eax,0
|
||||
inc esi
|
||||
cmp esi, HALL_DECOR_COUNT
|
||||
jb hall_render_lounge
|
||||
call RenderPatrons3D
|
||||
ret
|
||||
hall_render_bunker:
|
||||
|
|
@ -947,9 +992,35 @@ city_world_guard_right:
|
|||
ret
|
||||
RenderCityGuards3D ENDP
|
||||
|
||||
CanWalkHall3D PROC px:DWORD,py:DWORD
|
||||
CanWalkHall3D PROC uses esi ebx px:DWORD,py:DWORD
|
||||
cmp hallLevel3D, 0
|
||||
jne hall_collision_bunker
|
||||
xor esi, esi
|
||||
hall_collision_decor:
|
||||
imul ebx, esi, SIZEOF CityProp3D
|
||||
mov eax, px
|
||||
sub eax, hallLoungeDecor3D[ebx].posX
|
||||
test eax, eax
|
||||
jns @F
|
||||
neg eax
|
||||
@@:
|
||||
mov ecx, hallLoungeDecor3D[ebx].worldW
|
||||
shr ecx, 1
|
||||
add ecx, 9830
|
||||
cmp eax, ecx
|
||||
ja hall_collision_next_decor
|
||||
mov eax, py
|
||||
sub eax, hallLoungeDecor3D[ebx].posY
|
||||
test eax, eax
|
||||
jns @F
|
||||
neg eax
|
||||
@@:
|
||||
cmp eax, FP_1*2/5
|
||||
jbe hall_collision_blocked
|
||||
hall_collision_next_decor:
|
||||
inc esi
|
||||
cmp esi, HALL_DECOR_COUNT
|
||||
jb hall_collision_decor
|
||||
; Stage and wings are solid: the audience stays in the cabaret's front aisle.
|
||||
cmp px, 10*FP_1-9830
|
||||
jl hall_collision_stage_clear
|
||||
|
|
|
|||
|
|
@ -10,32 +10,33 @@ merchantReactionKind3D dd 1
|
|||
merchantPreviousFocus3D dd 0
|
||||
merchantMessage3D dd 0
|
||||
merchantPrices3D dd 0,3000,3000,10000,12000,15000,17000,18000,20000,22000,22000,23000,24000
|
||||
merchantGrey3D db "SILVER / GREY",0
|
||||
merchantBlue3D db "SAPPHIRE WAVE",0
|
||||
merchantRed3D db "CRIMSON CROSS",0
|
||||
merchantGold3D db "GOLDEN SUN",0
|
||||
merchantSkull3D db "SKULL / ROSES",0
|
||||
merchantClover3D db "CLOVERPIT",0
|
||||
merchantArcane3D db "ARCANE",0
|
||||
merchantNoir3D db "NOIR",0
|
||||
merchantDiamond3D db "DIAMOND",0
|
||||
merchantRider3D db "RIDER",0
|
||||
merchantBee3D db "BEE",0
|
||||
merchantFan3D db "FAN",0
|
||||
merchantWeb3D db "WEB",0
|
||||
merchantGrey3D db 209,197,208,197,193,208,206,0
|
||||
merchantBlue3D db 209,192,207,212,200,208,206,194,192,223,32,194,206,203,205,192,0
|
||||
merchantRed3D db 193,192,195,208,206,194,219,201,32,202,208,197,209,210,0
|
||||
merchantGold3D db 199,206,203,206,210,206,197,32,209,206,203,205,214,197,0
|
||||
merchantSkull3D db 215,197,208,197,207,32,200,32,208,206,199,219,0
|
||||
merchantClover3D db 202,203,197,194,197,208,0
|
||||
merchantArcane3D db 192,208,202,192,205,192,0
|
||||
merchantNoir3D db 205,211,192,208,0
|
||||
merchantDiamond3D db 192,203,204,192,199,0
|
||||
merchantRider3D db 205,192,197,199,196,205,200,202,0
|
||||
merchantBee3D db 207,215,197,203,192,0
|
||||
merchantFan3D db 194,197,197,208,0
|
||||
merchantWeb3D db 207,192,211,210,200,205,192,0
|
||||
merchantNames3D dd OFFSET merchantGrey3D,OFFSET merchantBlue3D,OFFSET merchantRed3D
|
||||
dd OFFSET merchantGold3D,OFFSET merchantSkull3D,OFFSET merchantClover3D
|
||||
dd OFFSET merchantArcane3D,OFFSET merchantNoir3D,OFFSET merchantDiamond3D
|
||||
dd OFFSET merchantRider3D,OFFSET merchantBee3D,OFFSET merchantFan3D,OFFSET merchantWeb3D
|
||||
merchantTitle3D db "SIDOROVICH",0
|
||||
merchantStock3D db "BACKS",0
|
||||
merchantBuy3D db "BUY / EQUIP",0
|
||||
merchantOwned3D db "OWNED",0
|
||||
merchantEquipped3D db "EQUIPPED",0
|
||||
merchantPoor3D db "NOT ENOUGH CHIPS",0
|
||||
merchantShopKeys3D db "UP/DOWN ENTER: BUY ESC: HALL",0
|
||||
merchantHello3D db "TAKE A LOOK.",0
|
||||
merchantThanks3D db "A GOOD CHOICE.",0
|
||||
merchantTitle3D db 209,200,196,206,208,206,194,200,215,0
|
||||
merchantStock3D db 208,211,193,192,216,202,200,0
|
||||
merchantBuy3D db 202,211,207,200,210,220,0
|
||||
merchantOwned3D db 197,209,210,220,0
|
||||
merchantEquipped3D db 205,192,196,197,210,206,0
|
||||
merchantPoor3D db 204,192,203,206,32,212,200,216,197,202,0
|
||||
merchantShopKeys3D db 194,194,197,208,213,47,194,205,200,199,32,32,69,78,84,69,82,58,32,202,211,207,200,210,220,32,32,69,83,67,58,32
|
||||
db 213,206,203,203,0
|
||||
merchantHello3D db 207,206,209,204,206,210,208,200,44,32,215,210,206,32,197,209,210,220,46,0
|
||||
merchantThanks3D db 213,206,208,206,216,200,201,32,194,219,193,206,208,46,0
|
||||
merchantArrowUp3D db "^",0
|
||||
merchantArrowDown3D db "v",0
|
||||
.code
|
||||
|
|
|
|||
626
src_graphics/native_coin.inc
Normal file
|
|
@ -0,0 +1,626 @@
|
|||
InitNativeCoin3D PROC
|
||||
mov coin3d_state,COIN_IDLE
|
||||
mov coin3d_timer,0
|
||||
mov coin3d_streak,0
|
||||
mov coin3d_win,0
|
||||
mov coin3d_choice,1
|
||||
mov coin3d_result,1
|
||||
mov coinExitQueued3D,0
|
||||
mov coinError3D,0
|
||||
cmp coin3d_bet,50
|
||||
jae @F
|
||||
mov coin3d_bet,50
|
||||
@@:
|
||||
cmp coin3d_bet,5000
|
||||
jbe @F
|
||||
mov coin3d_bet,5000
|
||||
@@:
|
||||
call LoadNativeCoinArt3D
|
||||
call OpenCoinDetail3D
|
||||
ret
|
||||
InitNativeCoin3D ENDP
|
||||
|
||||
LoadNativeCoinArt3D PROC
|
||||
cmp coinArtReady3D,1
|
||||
je coin_art_loaded
|
||||
invoke LoadAnimPack3D,OFFSET coinTableArt3D,OFFSET coinTablePath3D
|
||||
invoke LoadAnimPack3D,OFFSET coinFacesArt3D,OFFSET coinFacesPath3D
|
||||
invoke LoadAnimPack3D,OFFSET coinHandsArt3D,OFFSET coinHandsPath3D
|
||||
invoke ValidateCityPack3D,OFFSET coinTableArt3D,640,480,1
|
||||
invoke ValidateCityPack3D,OFFSET coinFacesArt3D,128,128,2
|
||||
invoke ValidateCityPack3D,OFFSET coinHandsArt3D,224,224,16
|
||||
cmp coinTableArt3D.pixels,0
|
||||
je coin_art_failed
|
||||
cmp coinFacesArt3D.pixels,0
|
||||
je coin_art_failed
|
||||
cmp coinHandsArt3D.pixels,0
|
||||
je coin_art_failed
|
||||
mov coinArtReady3D,1
|
||||
coin_art_loaded:
|
||||
mov eax,1
|
||||
ret
|
||||
coin_art_failed:
|
||||
call FreeNativeCoinArt3D
|
||||
xor eax,eax
|
||||
ret
|
||||
LoadNativeCoinArt3D ENDP
|
||||
|
||||
FreeNativeCoinArt3D PROC
|
||||
call CloseCoinDetail3D
|
||||
invoke FreeAnimPack3D,OFFSET coinTableArt3D
|
||||
invoke FreeAnimPack3D,OFFSET coinFacesArt3D
|
||||
invoke FreeAnimPack3D,OFFSET coinHandsArt3D
|
||||
mov coinArtReady3D,0
|
||||
ret
|
||||
FreeNativeCoinArt3D ENDP
|
||||
|
||||
CoinEscape3D PROC
|
||||
mov paused3D,0
|
||||
cmp coin3d_state,COIN_TOSS
|
||||
jne coin_leave_hall
|
||||
mov coinExitQueued3D,1
|
||||
call ClearKeys3D
|
||||
ret
|
||||
coin_leave_hall:
|
||||
call CloseCoinDetail3D
|
||||
mov coinExitQueued3D,0
|
||||
mov engineMode,MODE_WALK
|
||||
call ClearKeys3D
|
||||
invoke PlayCasinoSound3D,0,0,0
|
||||
ret
|
||||
CoinEscape3D ENDP
|
||||
|
||||
; A paid flip settles once, even if Escape was pressed while it was in the air.
|
||||
CoinSettle3D PROC
|
||||
cmp coin3d_state,COIN_TOSS
|
||||
jne coin_settle_done
|
||||
mov coin3d_timer,COIN_TOTAL_MS
|
||||
mov coin3d_win,0
|
||||
mov eax,coin3d_choice
|
||||
cmp eax,coin3d_result
|
||||
jne coin_settle_loss
|
||||
inc coin3d_streak
|
||||
mov eax,coin3d_bet
|
||||
shl eax,1
|
||||
mov coin3d_win,eax
|
||||
add bankroll,eax
|
||||
jnc @F
|
||||
mov bankroll,1000000000
|
||||
@@:
|
||||
cmp bankroll,1000000000
|
||||
jbe @F
|
||||
mov bankroll,1000000000
|
||||
@@:
|
||||
invoke PlayCasinoSound3D,OFFSET soundCoinDing,0,1
|
||||
jmp coin_settle_save
|
||||
coin_settle_loss:
|
||||
mov coin3d_streak,0
|
||||
invoke PlayCasinoSound3D,OFFSET soundLose,0,1
|
||||
coin_settle_save:
|
||||
mov coin3d_state,COIN_RESULT
|
||||
call SaveProgress3D
|
||||
coin_settle_done:
|
||||
ret
|
||||
CoinSettle3D ENDP
|
||||
|
||||
HandleNativeCoin3D PROC uses ebx
|
||||
cmp mouseClick3D,0
|
||||
je coin_native_state
|
||||
cmp mouseY3D,3
|
||||
jb coin_native_state
|
||||
cmp mouseY3D,17
|
||||
jae coin_native_state
|
||||
cmp mouseX3D,252
|
||||
jb coin_native_view
|
||||
cmp mouseX3D,312
|
||||
jae coin_native_state
|
||||
mov mouseClick3D,0
|
||||
call CoinEscape3D
|
||||
cmp engineMode,MODE_WALK
|
||||
je coin_native_done
|
||||
jmp coin_native_state
|
||||
coin_native_view:
|
||||
cmp mouseX3D,198
|
||||
jb coin_native_state
|
||||
cmp mouseX3D,246
|
||||
jae coin_native_state
|
||||
mov mouseClick3D,0
|
||||
call OpenCoinDetail3D
|
||||
coin_native_state:
|
||||
cmp coin3d_state,COIN_TOSS
|
||||
jne coin_native_result
|
||||
mov eax,coin3d_timer
|
||||
add eax,deltaTime3D
|
||||
jc coin_native_settle
|
||||
cmp eax,COIN_TOTAL_MS
|
||||
jae coin_native_settle
|
||||
mov coin3d_timer,eax
|
||||
ret
|
||||
coin_native_settle:
|
||||
call CoinSettle3D
|
||||
cmp coinExitQueued3D,0
|
||||
je coin_native_done
|
||||
call CoinEscape3D
|
||||
ret
|
||||
coin_native_result:
|
||||
cmp coin3d_state,COIN_RESULT
|
||||
jne coin_native_mouse
|
||||
invoke Pressed3D,20h
|
||||
test eax,eax
|
||||
jnz coin_native_again
|
||||
invoke Pressed3D,0Dh
|
||||
test eax,eax
|
||||
jnz coin_native_again
|
||||
cmp mouseClick3D,0
|
||||
je coin_native_done
|
||||
mov mouseClick3D,0
|
||||
cmp mouseY3D,219
|
||||
jb coin_native_done
|
||||
cmp mouseY3D,237
|
||||
jae coin_native_done
|
||||
cmp mouseX3D,220
|
||||
jb coin_native_done
|
||||
cmp mouseX3D,312
|
||||
jae coin_native_done
|
||||
coin_native_again:
|
||||
mov coin3d_state,COIN_IDLE
|
||||
mov coin3d_timer,0
|
||||
mov coinError3D,0
|
||||
mov mouseClick3D,0
|
||||
call ClearKeys3D
|
||||
ret
|
||||
coin_native_mouse:
|
||||
cmp mouseClick3D,0
|
||||
je coin_native_keys
|
||||
mov mouseClick3D,0
|
||||
cmp mouseY3D,199
|
||||
jb coin_native_keys
|
||||
cmp mouseY3D,215
|
||||
jae coin_native_sides
|
||||
cmp mouseX3D,118
|
||||
jb coin_native_keys
|
||||
cmp mouseX3D,134
|
||||
jb coin_native_less
|
||||
cmp mouseX3D,140
|
||||
jb coin_native_keys
|
||||
cmp mouseX3D,156
|
||||
jb coin_native_more
|
||||
jmp coin_native_keys
|
||||
coin_native_sides:
|
||||
cmp mouseY3D,219
|
||||
jb coin_native_keys
|
||||
cmp mouseY3D,237
|
||||
jae coin_native_keys
|
||||
cmp mouseX3D,8
|
||||
jb coin_native_keys
|
||||
cmp mouseX3D,98
|
||||
jb coin_native_heads
|
||||
cmp mouseX3D,106
|
||||
jb coin_native_keys
|
||||
cmp mouseX3D,196
|
||||
jb coin_native_tails
|
||||
cmp mouseX3D,220
|
||||
jb coin_native_keys
|
||||
cmp mouseX3D,312
|
||||
jb coin_native_start
|
||||
coin_native_keys:
|
||||
invoke Pressed3D,26h
|
||||
test eax,eax
|
||||
jnz coin_native_more
|
||||
invoke Pressed3D,57h
|
||||
test eax,eax
|
||||
jnz coin_native_more
|
||||
invoke Pressed3D,28h
|
||||
test eax,eax
|
||||
jnz coin_native_less
|
||||
invoke Pressed3D,53h
|
||||
test eax,eax
|
||||
jnz coin_native_less
|
||||
invoke Pressed3D,31h
|
||||
test eax,eax
|
||||
jnz coin_native_heads
|
||||
invoke Pressed3D,32h
|
||||
test eax,eax
|
||||
jnz coin_native_tails
|
||||
invoke Pressed3D,20h
|
||||
test eax,eax
|
||||
jnz coin_native_start
|
||||
invoke Pressed3D,0Dh
|
||||
test eax,eax
|
||||
jnz coin_native_start
|
||||
ret
|
||||
coin_native_more:
|
||||
cmp coin3d_bet,5000
|
||||
jae coin_native_done
|
||||
add coin3d_bet,50
|
||||
mov coinError3D,0
|
||||
ret
|
||||
coin_native_less:
|
||||
cmp coin3d_bet,50
|
||||
jbe coin_native_done
|
||||
sub coin3d_bet,50
|
||||
mov coinError3D,0
|
||||
ret
|
||||
coin_native_heads:
|
||||
mov coin3d_choice,1
|
||||
ret
|
||||
coin_native_tails:
|
||||
mov coin3d_choice,2
|
||||
ret
|
||||
coin_native_start:
|
||||
cmp coinArtReady3D,1
|
||||
jne coin_native_done
|
||||
mov eax,coin3d_bet
|
||||
cmp eax,50
|
||||
jb coin_native_done
|
||||
cmp eax,5000
|
||||
ja coin_native_done
|
||||
cmp eax,bankroll
|
||||
ja coin_native_insufficient
|
||||
sub bankroll,eax
|
||||
mov coin3d_state,COIN_TOSS
|
||||
mov coin3d_timer,0
|
||||
mov coin3d_win,0
|
||||
mov coinExitQueued3D,0
|
||||
mov coinError3D,0
|
||||
mov eax,coin3d_choice
|
||||
dec eax
|
||||
shl eax,8
|
||||
add eax,96
|
||||
mov coinStartPhase3D,eax
|
||||
invoke RandomRange3D,2
|
||||
inc eax
|
||||
mov coin3d_result,eax
|
||||
call SaveProgress3D
|
||||
invoke PlayCasinoSound3D,OFFSET soundCoin,0,1
|
||||
call ClearKeys3D
|
||||
ret
|
||||
coin_native_insufficient:
|
||||
mov coinError3D,1
|
||||
coin_native_done:
|
||||
ret
|
||||
HandleNativeCoin3D ENDP
|
||||
|
||||
; Derive pose from absolute elapsed time; never alter bank, outcome or RNG here.
|
||||
CoinPose3D PROC uses ebx esi timeMs:DWORD
|
||||
local phase:DWORD,flightTime:DWORD,bounceTime:DWORD
|
||||
mov coinX3D,414
|
||||
mov coinY3D,266
|
||||
mov coinGroundY3D,344
|
||||
mov coinWidth3D,32
|
||||
mov coinHeight3D,12
|
||||
mov coinShadowRadius3D,30
|
||||
mov coinShadowAlpha3D,90
|
||||
mov coinHandY3D,240
|
||||
mov coinHandPose3D,0
|
||||
mov eax,coin3d_choice
|
||||
dec eax
|
||||
mov coinFace3D,eax
|
||||
shl eax,8
|
||||
mov coinAngle3D,eax
|
||||
cmp coin3d_state,COIN_IDLE
|
||||
je coin_pose_done
|
||||
mov eax,timeMs
|
||||
cmp eax,COIN_RELEASE_MS
|
||||
jae coin_pose_air
|
||||
xor edx,edx
|
||||
mov ecx,60
|
||||
div ecx
|
||||
mov coinHandPose3D,eax
|
||||
ret
|
||||
coin_pose_air:
|
||||
sub eax,COIN_RELEASE_MS
|
||||
mov flightTime,eax
|
||||
mov ebx,eax
|
||||
xor edx,edx
|
||||
mov ecx,65
|
||||
div ecx
|
||||
add eax,5
|
||||
cmp eax,15
|
||||
jbe @F
|
||||
mov eax,15
|
||||
@@:
|
||||
mov coinHandPose3D,eax
|
||||
cmp ebx,200
|
||||
jb @F
|
||||
sub ebx,200
|
||||
shr ebx,1
|
||||
cmp ebx,300
|
||||
jbe coin_pose_withdraw
|
||||
mov ebx,300
|
||||
coin_pose_withdraw:
|
||||
add coinHandY3D,ebx
|
||||
@@:
|
||||
cmp flightTime,COIN_FLIGHT_MS
|
||||
jae coin_pose_landing
|
||||
mov eax,flightTime
|
||||
shl eax,16
|
||||
xor edx,edx
|
||||
mov ecx,COIN_FLIGHT_MS
|
||||
div ecx
|
||||
mov phase,eax
|
||||
imul eax,94
|
||||
shr eax,16
|
||||
sub coinX3D,eax
|
||||
; Ballistic height from the thumb to the felt, with no mid-air easing/hover.
|
||||
mov eax,FP_1
|
||||
sub eax,phase
|
||||
mul phase
|
||||
shrd eax,edx,16
|
||||
imul eax,480
|
||||
shr eax,16
|
||||
mov ebx,FP_1
|
||||
sub ebx,phase
|
||||
imul ebx,78
|
||||
shr ebx,16
|
||||
add eax,ebx
|
||||
mov ebx,coinGroundY3D
|
||||
sub ebx,eax
|
||||
mov coinY3D,ebx
|
||||
shr eax,2
|
||||
sub coinShadowAlpha3D,eax
|
||||
mov eax,coin3d_result
|
||||
dec eax
|
||||
shl eax,8
|
||||
add eax,2*512
|
||||
sub eax,coinStartPhase3D
|
||||
mul phase
|
||||
shrd eax,edx,16
|
||||
add eax,coinStartPhase3D
|
||||
and eax,511
|
||||
mov coinAngle3D,eax
|
||||
mov ebx,tableCos[eax*4]
|
||||
mov coinFace3D,0
|
||||
test ebx,ebx
|
||||
jns @F
|
||||
neg ebx
|
||||
mov coinFace3D,1
|
||||
@@:
|
||||
imul ebx,32
|
||||
shr ebx,16
|
||||
cmp ebx,3
|
||||
jae @F
|
||||
mov ebx,3
|
||||
@@:
|
||||
mov coinHeight3D,ebx
|
||||
ret
|
||||
coin_pose_landing:
|
||||
mov coinX3D,320
|
||||
mov coinY3D,344
|
||||
mov coinGroundY3D,344
|
||||
mov coinHeight3D,32
|
||||
mov coinShadowAlpha3D,110
|
||||
mov eax,coin3d_result
|
||||
dec eax
|
||||
mov coinFace3D,eax
|
||||
shl eax,8
|
||||
mov coinAngle3D,eax
|
||||
mov eax,flightTime
|
||||
sub eax,COIN_FLIGHT_MS
|
||||
mov bounceTime,eax
|
||||
cmp eax,60
|
||||
jbe @F
|
||||
mov eax,60
|
||||
@@:
|
||||
mov ebx,eax
|
||||
imul eax,18
|
||||
xor edx,edx
|
||||
mov ecx,60
|
||||
div ecx
|
||||
sub coinHeight3D,eax
|
||||
mov eax,ebx
|
||||
imul eax,24
|
||||
xor edx,edx
|
||||
div ecx
|
||||
add coinWidth3D,eax
|
||||
mov eax,bounceTime
|
||||
mov ebx,180
|
||||
mov esi,72
|
||||
cmp eax,180
|
||||
jb coin_pose_bounce
|
||||
sub eax,180
|
||||
mov ebx,120
|
||||
mov esi,24
|
||||
cmp eax,120
|
||||
jae coin_pose_done
|
||||
coin_pose_bounce:
|
||||
shl eax,16
|
||||
xor edx,edx
|
||||
div ebx
|
||||
mov ecx,eax
|
||||
neg eax
|
||||
add eax,FP_1
|
||||
mul ecx
|
||||
shrd eax,edx,16
|
||||
imul eax,esi
|
||||
shr eax,16
|
||||
sub coinY3D,eax
|
||||
coin_pose_done:
|
||||
ret
|
||||
CoinPose3D ENDP
|
||||
|
||||
; Fractional shadow on actual framebuffer pixels, rather than a black rectangular sprite.
|
||||
DrawCoinShadow3D PROC uses ebx esi edi centerX:DWORD,centerY:DWORD,radiusX:DWORD,radiusY:DWORD,opacity:DWORD
|
||||
local row:DWORD,column:DWORD,dy2:DWORD,limit:DWORD,inverse:DWORD
|
||||
mov eax,255
|
||||
sub eax,opacity
|
||||
mov inverse,eax
|
||||
mov eax,radiusX
|
||||
imul eax,eax
|
||||
mov ebx,radiusY
|
||||
imul ebx,ebx
|
||||
imul eax,ebx
|
||||
mov limit,eax
|
||||
mov eax,centerY
|
||||
sub eax,radiusY
|
||||
mov row,eax
|
||||
coin_shadow_row:
|
||||
mov eax,row
|
||||
sub eax,centerY
|
||||
imul eax,eax
|
||||
imul eax,radiusX
|
||||
imul eax,radiusX
|
||||
mov dy2,eax
|
||||
mov eax,centerX
|
||||
sub eax,radiusX
|
||||
mov column,eax
|
||||
coin_shadow_pixel:
|
||||
cmp row,SCREEN_H
|
||||
jae coin_shadow_next
|
||||
cmp column,SCREEN_W
|
||||
jae coin_shadow_next
|
||||
mov eax,column
|
||||
sub eax,centerX
|
||||
imul eax,eax
|
||||
imul eax,radiusY
|
||||
imul eax,radiusY
|
||||
add eax,dy2
|
||||
cmp eax,limit
|
||||
ja coin_shadow_next
|
||||
mov edi,row
|
||||
imul edi,SCREEN_W
|
||||
add edi,column
|
||||
lea edi,screenBuffer[edi*4]
|
||||
mov esi,[edi]
|
||||
xor ebx,ebx
|
||||
xor ecx,ecx
|
||||
coin_shadow_channel:
|
||||
mov eax,esi
|
||||
and eax,255
|
||||
imul eax,inverse
|
||||
add eax,128
|
||||
mov edx,eax
|
||||
shr edx,8
|
||||
add eax,edx
|
||||
shr eax,8
|
||||
shl eax,cl
|
||||
or ebx,eax
|
||||
shr esi,8
|
||||
add ecx,8
|
||||
cmp ecx,24
|
||||
jb coin_shadow_channel
|
||||
mov [edi],ebx
|
||||
coin_shadow_next:
|
||||
inc column
|
||||
mov eax,centerX
|
||||
add eax,radiusX
|
||||
cmp column,eax
|
||||
jle coin_shadow_pixel
|
||||
inc row
|
||||
mov eax,centerY
|
||||
add eax,radiusY
|
||||
cmp row,eax
|
||||
jle coin_shadow_row
|
||||
ret
|
||||
DrawCoinShadow3D ENDP
|
||||
|
||||
RenderNativeCoin3D PROC uses ebx esi edi
|
||||
local x:DWORD,y:DWORD,tint:DWORD
|
||||
cmp coinArtReady3D,1
|
||||
jne coin_render_missing
|
||||
mov esi,coinTableArt3D.pixels
|
||||
lea edi,screenBuffer
|
||||
mov ecx,SCREEN_SIZE
|
||||
rep movsd
|
||||
invoke CoinPose3D,coin3d_timer
|
||||
cmp coin3d_timer,COIN_RELEASE_MS
|
||||
jae coin_render_released
|
||||
invoke DrawAnimSprite3D,OFFSET coinHandsArt3D,coinHandPose3D,320,coinHandY3D,240,240
|
||||
jmp coin_render_hud
|
||||
coin_render_released:
|
||||
mov eax,coinGroundY3D
|
||||
add eax,14
|
||||
invoke DrawCoinShadow3D,coinX3D,eax,coinShadowRadius3D,5,coinShadowAlpha3D
|
||||
invoke DrawAnimSprite3D,OFFSET coinHandsArt3D,coinHandPose3D,320,coinHandY3D,240,240
|
||||
mov eax,coinWidth3D
|
||||
shr eax,1
|
||||
neg eax
|
||||
add eax,coinX3D
|
||||
mov x,eax
|
||||
mov eax,coinHeight3D
|
||||
shr eax,1
|
||||
neg eax
|
||||
add eax,coinY3D
|
||||
mov y,eax
|
||||
add eax,2
|
||||
invoke DrawAnimSprite3D,OFFSET coinFacesArt3D,coinFace3D,x,eax,coinWidth3D,coinHeight3D
|
||||
invoke DrawAnimSprite3D,OFFSET coinFacesArt3D,coinFace3D,x,y,coinWidth3D,coinHeight3D
|
||||
coin_render_hud:
|
||||
invoke DrawBox,0,0,320,20,0014191Dh
|
||||
invoke DrawString8x8,12,6,OFFSET coinTitle3D,00E5D29Eh
|
||||
invoke DrawBoxBorder,198,3,48,14,00252D2Ah,0086754Eh,1
|
||||
invoke DrawString8x8,210,6,OFFSET coinDetailView3D,00E5D29Eh
|
||||
invoke DrawBoxBorder,252,3,60,14,00252D2Ah,0086754Eh,1
|
||||
invoke DrawString8x8,266,6,OFFSET coinExitText3D,00E5D29Eh
|
||||
invoke DrawBox,4,23,138,15,0014191Dh
|
||||
invoke DrawString8x8,8,26,OFFSET coinBankText3D,00E5D29Eh
|
||||
invoke DrawNumber,60,26,bankroll,00FFFFFFh
|
||||
invoke DrawBox,0,194,320,46,0014191Dh
|
||||
cmp coin3d_state,COIN_TOSS
|
||||
je coin_render_toss_hud
|
||||
cmp coin3d_state,COIN_RESULT
|
||||
je coin_render_result_hud
|
||||
invoke DrawString8x8,8,202,OFFSET coinStakeText3D,00E5D29Eh
|
||||
invoke DrawNumber,72,202,coin3d_bet,00FFFFFFh
|
||||
invoke DrawBoxBorder,118,199,16,16,003B3024h,00C6AA66h,1
|
||||
invoke DrawString8x8,122,203,OFFSET coinMinusText3D,00FFFFFFh
|
||||
invoke DrawBoxBorder,140,199,16,16,003B3024h,00C6AA66h,1
|
||||
invoke DrawString8x8,144,203,OFFSET coinPlusText3D,00FFFFFFh
|
||||
cmp coinError3D,0
|
||||
je @F
|
||||
invoke DrawString8x8,178,202,OFFSET coinLowBankText3D,00E99383h
|
||||
@@:
|
||||
mov tint,0086754Eh
|
||||
cmp coin3d_choice,1
|
||||
jne @F
|
||||
mov tint,00EAC96Dh
|
||||
@@:
|
||||
invoke DrawBoxBorder,8,219,90,18,00252D2Ah,tint,1
|
||||
invoke DrawString8x8,34,224,OFFSET coinHeadsText3D,00F4E7C8h
|
||||
mov tint,0086754Eh
|
||||
cmp coin3d_choice,2
|
||||
jne @F
|
||||
mov tint,00EAC96Dh
|
||||
@@:
|
||||
invoke DrawBoxBorder,106,219,90,18,00252D2Ah,tint,1
|
||||
invoke DrawString8x8,132,224,OFFSET coinTailsText3D,00F4E7C8h
|
||||
invoke DrawBoxBorder,220,219,92,18,00423929h,00C6AA66h,1
|
||||
invoke DrawString8x8,242,224,OFFSET coinFlipText3D,00FFFFFFh
|
||||
jmp coin_render_done
|
||||
coin_render_toss_hud:
|
||||
mov eax,OFFSET coinTossText3D
|
||||
cmp coin3d_timer,COIN_RELEASE_MS
|
||||
jae @F
|
||||
mov eax,OFFSET coinPrepareText3D
|
||||
@@:
|
||||
cmp coin3d_timer,COIN_LAND_MS
|
||||
jb @F
|
||||
mov eax,OFFSET coinLandingText3D
|
||||
@@:
|
||||
cmp coinExitQueued3D,0
|
||||
je @F
|
||||
mov eax,OFFSET coinLeavingText3D
|
||||
@@:
|
||||
invoke DrawString8x8,82,214,eax,00E5D29Eh
|
||||
jmp coin_render_done
|
||||
coin_render_result_hud:
|
||||
mov eax,OFFSET coinHeadsText3D
|
||||
cmp coin3d_result,1
|
||||
je @F
|
||||
mov eax,OFFSET coinTailsText3D
|
||||
@@:
|
||||
invoke DrawString8x8,8,202,eax,00E5D29Eh
|
||||
invoke DrawString8x8,140,202,OFFSET coinReturnText3D,00E5D29Eh
|
||||
invoke DrawNumber,212,202,coin3d_win,00FFFFFFh
|
||||
invoke DrawBoxBorder,220,219,92,18,003B3024h,00C6AA66h,1
|
||||
invoke DrawString8x8,238,224,OFFSET coinAgainText3D,00FFFFFFh
|
||||
jmp coin_render_done
|
||||
coin_render_missing:
|
||||
invoke DrawBox,0,0,320,240,0014191Dh
|
||||
invoke DrawString8x8,76,108,OFFSET coinMissingText3D,00E5D29Eh
|
||||
coin_render_done:
|
||||
call UpdateCoinDetail3D
|
||||
ret
|
||||
RenderNativeCoin3D ENDP
|
||||
|
||||
include src_graphics\coin_detail.inc
|
||||
58
src_graphics/native_coin_data.inc
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
COIN_IDLE equ 0
|
||||
COIN_TOSS equ 1
|
||||
COIN_RESULT equ 2
|
||||
COIN_RELEASE_MS equ 300
|
||||
COIN_FLIGHT_MS equ 720
|
||||
COIN_LAND_MS equ (COIN_RELEASE_MS+COIN_FLIGHT_MS)
|
||||
COIN_TOTAL_MS equ 1700
|
||||
InitNativeCoin3D PROTO
|
||||
HandleNativeCoin3D PROTO
|
||||
RenderNativeCoin3D PROTO
|
||||
LoadNativeCoinArt3D PROTO
|
||||
FreeNativeCoinArt3D PROTO
|
||||
CoinEscape3D PROTO
|
||||
CoinSettle3D PROTO
|
||||
CoinPose3D PROTO :DWORD
|
||||
DrawCoinShadow3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
ValidateCityPack3D PROTO :DWORD,:DWORD,:DWORD,:DWORD
|
||||
.data
|
||||
coinTableArt3D AnimPack3D <>
|
||||
coinFacesArt3D AnimPack3D <>
|
||||
coinHandsArt3D AnimPack3D <>
|
||||
coinTablePath3D db "assets\animations\coin\table-v1.bin",0
|
||||
coinFacesPath3D db "assets\animations\coin\faces-v1.bin",0
|
||||
coinHandsPath3D db "assets\animations\coin\hands-v2.bin",0
|
||||
coinArtReady3D dd 0
|
||||
coinExitQueued3D dd 0
|
||||
coinStartPhase3D dd 0
|
||||
coinAngle3D dd 0
|
||||
coinX3D dd 433
|
||||
coinY3D dd 313
|
||||
coinGroundY3D dd 344
|
||||
coinWidth3D dd 56
|
||||
coinHeight3D dd 56
|
||||
coinFace3D dd 0
|
||||
coinHandPose3D dd 0
|
||||
coinHandY3D dd 250
|
||||
coinShadowRadius3D dd 30
|
||||
coinShadowAlpha3D dd 70
|
||||
coinTitle3D db 204,206,205,197,210,202,192,0
|
||||
coinHeadsText3D db 206,208,168,203,0
|
||||
coinTailsText3D db 208,197,216,202,192,0
|
||||
coinFlipText3D db 193,208,206,209,206,202,0
|
||||
coinAgainText3D db 197,217,168,32,208,192,199,0
|
||||
coinExitText3D db 194,219,213,206,196,0
|
||||
coinBankText3D db 193,192,205,202,32,36,0
|
||||
coinStakeText3D db 209,210,192,194,202,192,0
|
||||
coinReturnText3D db 194,219,207,203,192,210,192,0
|
||||
coinLeavingText3D db 194,219,213,206,196,32,207,206,209,203,197,32,193,208,206,209,202,192,0
|
||||
coinTossText3D db 194,32,207,206,203,168,210,197,0
|
||||
coinLandingText3D db 207,208,200,199,197,204,203,197,205,200,197,0
|
||||
coinPrepareText3D db 193,208,206,209,192,197,204,0
|
||||
coinMissingText3D db 205,197,210,32,209,207,208,192,201,210,206,194,0
|
||||
coinLowBankText3D db 204,192,203,206,32,212,200,216,197,202,0
|
||||
coinPlusText3D db "+",0
|
||||
coinMinusText3D db "-",0
|
||||
coinError3D dd 0
|
||||
include src_graphics\coin_detail_data.inc
|
||||
.code
|
||||
570
src_graphics/native_slots.inc
Normal file
|
|
@ -0,0 +1,570 @@
|
|||
FreeNativeSlots3D PROC
|
||||
invoke FreeAnimPack3D, OFFSET slotCabinetPack3D
|
||||
invoke FreeAnimPack3D, OFFSET slotSymbolsPack3D
|
||||
ret
|
||||
FreeNativeSlots3D ENDP
|
||||
|
||||
InitNativeSlots3D PROC
|
||||
invoke LoadAnimPack3D, OFFSET slotCabinetPack3D, OFFSET slotCabinetPath3D
|
||||
test eax,eax
|
||||
jz slot_init_fail
|
||||
cmp slotCabinetPack3D.imageWidth,640
|
||||
jne slot_init_fail
|
||||
cmp slotCabinetPack3D.height,480
|
||||
jne slot_init_fail
|
||||
cmp slotCabinetPack3D.frames,1
|
||||
jne slot_init_fail
|
||||
invoke LoadAnimPack3D, OFFSET slotSymbolsPack3D, OFFSET slotSymbolsPath3D
|
||||
test eax,eax
|
||||
jz slot_init_fail
|
||||
cmp slotSymbolsPack3D.imageWidth,64
|
||||
jne slot_init_fail
|
||||
cmp slotSymbolsPack3D.height,64
|
||||
jne slot_init_fail
|
||||
cmp slotSymbolsPack3D.frames,8
|
||||
jne slot_init_fail
|
||||
mov slotSpinState,SLOT_READY
|
||||
mov slotSpinTimer,0
|
||||
mov slotWinAmount,0
|
||||
mov slotStake3D,0
|
||||
mov slotLeaveAfter3D,0
|
||||
mov slotPaytable3D,0
|
||||
mov slotError3D,0
|
||||
mov slotEffects3D,0
|
||||
mov slotBetIndex3D,1
|
||||
mov slotBet,50
|
||||
mov cardExitActive3D,0
|
||||
mov paused3D,0
|
||||
call ClearKeys3D
|
||||
mov eax,1
|
||||
ret
|
||||
slot_init_fail:
|
||||
call FreeNativeSlots3D
|
||||
xor eax,eax
|
||||
ret
|
||||
InitNativeSlots3D ENDP
|
||||
|
||||
; Results are sampled once at stake debit. Rendering never consumes RNG or pays.
|
||||
StartNativeSlots3D PROC uses ebx esi
|
||||
cmp slotSpinState,SLOT_SPIN
|
||||
je slot_start_done
|
||||
cmp slotPaytable3D,0
|
||||
jne slot_start_done
|
||||
cmp slotCabinetPack3D.pixels,0
|
||||
je slot_start_done
|
||||
cmp slotSymbolsPack3D.pixels,0
|
||||
je slot_start_done
|
||||
mov eax,slotBet
|
||||
test eax,eax
|
||||
jz slot_start_done
|
||||
cmp eax,10000
|
||||
ja slot_start_done
|
||||
cmp eax,bankroll
|
||||
ja slot_start_money
|
||||
sub bankroll,eax
|
||||
mov slotStake3D,eax
|
||||
mov slotSpinState,SLOT_SPIN
|
||||
mov slotSpinTimer,0
|
||||
mov slotWinAmount,0
|
||||
mov slotLeaveAfter3D,0
|
||||
mov slotError3D,0
|
||||
mov slotEffects3D,0
|
||||
xor esi,esi
|
||||
slot_start_reel:
|
||||
mov eax,slotStops3D[esi*4]
|
||||
mov slotStartStops3D[esi*4],eax
|
||||
invoke RandomRange3D,20
|
||||
mov slotTargets3D[esi*4],eax
|
||||
mov edx,slotStrip3D[eax*4]
|
||||
mov slotReel1[esi*4],edx
|
||||
sub eax,slotStartStops3D[esi*4]
|
||||
jns @F
|
||||
add eax,20
|
||||
@@:
|
||||
add eax,slotCycles3D[esi*4]
|
||||
shl eax,6
|
||||
mov slotTravel3D[esi*4],eax
|
||||
inc esi
|
||||
cmp esi,3
|
||||
jb slot_start_reel
|
||||
call SaveProgress3D
|
||||
invoke PlayCasinoSound3D, OFFSET soundSlotSpin,0,1
|
||||
ret
|
||||
slot_start_money:
|
||||
mov slotError3D,1
|
||||
slot_start_done:
|
||||
ret
|
||||
StartNativeSlots3D ENDP
|
||||
|
||||
; Gross multipliers. A cherry pair pays 2x, any other pair returns the stake.
|
||||
SlotMultiplier3D PROC first:DWORD,second:DWORD,third:DWORD
|
||||
mov eax,first
|
||||
cmp eax,7
|
||||
ja slot_multiplier_zero
|
||||
cmp second,7
|
||||
ja slot_multiplier_zero
|
||||
cmp third,7
|
||||
ja slot_multiplier_zero
|
||||
cmp eax,second
|
||||
jne slot_multiplier_other_pair
|
||||
cmp eax,third
|
||||
jne slot_multiplier_pair
|
||||
mov eax,slotTriple3D[eax*4]
|
||||
ret
|
||||
slot_multiplier_other_pair:
|
||||
cmp eax,third
|
||||
je slot_multiplier_pair
|
||||
mov eax,second
|
||||
cmp eax,third
|
||||
jne slot_multiplier_zero
|
||||
slot_multiplier_pair:
|
||||
cmp eax,1
|
||||
jne @F
|
||||
mov eax,2
|
||||
ret
|
||||
@@:
|
||||
mov eax,1
|
||||
ret
|
||||
slot_multiplier_zero:
|
||||
xor eax,eax
|
||||
ret
|
||||
SlotMultiplier3D ENDP
|
||||
|
||||
SettleNativeSlots3D PROC uses esi
|
||||
cmp slotSpinState,SLOT_SPIN
|
||||
jne slot_settle_done
|
||||
invoke SlotMultiplier3D,slotReel1,slotReel2,slotReel3
|
||||
mul slotStake3D
|
||||
mov slotWinAmount,eax
|
||||
add bankroll,eax
|
||||
jc slot_settle_cap
|
||||
cmp bankroll,1000000000
|
||||
jbe @F
|
||||
slot_settle_cap:
|
||||
mov bankroll,1000000000
|
||||
@@:
|
||||
xor esi,esi
|
||||
slot_settle_stops:
|
||||
mov eax,slotTargets3D[esi*4]
|
||||
mov slotStops3D[esi*4],eax
|
||||
inc esi
|
||||
cmp esi,3
|
||||
jb slot_settle_stops
|
||||
mov slotSpinTimer,3000
|
||||
mov slotSpinState,SLOT_RESULT
|
||||
mov slotEffects3D,0
|
||||
call SaveProgress3D
|
||||
cmp slotWinAmount,0
|
||||
je slot_settle_loss
|
||||
invoke PlayCasinoSound3D,OFFSET soundRoundWin,0,1
|
||||
jmp slot_settle_exit
|
||||
slot_settle_loss:
|
||||
invoke PlayCasinoSound3D,OFFSET soundRoundLose,0,1
|
||||
slot_settle_exit:
|
||||
cmp slotLeaveAfter3D,0
|
||||
je slot_settle_done
|
||||
call SlotEscape3D
|
||||
slot_settle_done:
|
||||
ret
|
||||
SettleNativeSlots3D ENDP
|
||||
|
||||
; Escape queues a safe exit during a paid spin; it never opens the pause menu.
|
||||
SlotEscape3D PROC
|
||||
mov paused3D,0
|
||||
cmp slotPaytable3D,0
|
||||
je @F
|
||||
mov slotPaytable3D,0
|
||||
call ClearKeys3D
|
||||
ret
|
||||
@@:
|
||||
cmp slotSpinState,SLOT_SPIN
|
||||
jne slot_exit_hall
|
||||
mov slotLeaveAfter3D,1
|
||||
call ClearKeys3D
|
||||
ret
|
||||
slot_exit_hall:
|
||||
mov slotLeaveAfter3D,0
|
||||
mov paused3D,0
|
||||
mov engineMode,MODE_WALK
|
||||
call ClearKeys3D
|
||||
invoke PlayCasinoSound3D,0,0,0
|
||||
ret
|
||||
SlotEscape3D ENDP
|
||||
|
||||
; A monotonic quadratic ease-out maps elapsed milliseconds to strip pixels.
|
||||
SlotReelPosition3D PROC uses ebx index:DWORD
|
||||
mov ebx,index
|
||||
cmp ebx,2
|
||||
ja slot_position_zero
|
||||
mov eax,slotStops3D[ebx*4]
|
||||
shl eax,6
|
||||
cmp slotSpinState,SLOT_SPIN
|
||||
jne slot_position_done
|
||||
mov eax,slotSpinTimer
|
||||
cmp eax,slotDurations3D[ebx*4]
|
||||
jae slot_position_end
|
||||
shl eax,10
|
||||
xor edx,edx
|
||||
div slotDurations3D[ebx*4]
|
||||
mov ecx,2048
|
||||
sub ecx,eax
|
||||
imul eax,ecx
|
||||
mul slotTravel3D[ebx*4]
|
||||
shrd eax,edx,20
|
||||
mov edx,slotStartStops3D[ebx*4]
|
||||
shl edx,6
|
||||
add eax,edx
|
||||
ret
|
||||
slot_position_end:
|
||||
mov eax,slotStartStops3D[ebx*4]
|
||||
shl eax,6
|
||||
add eax,slotTravel3D[ebx*4]
|
||||
slot_position_done:
|
||||
ret
|
||||
slot_position_zero:
|
||||
xor eax,eax
|
||||
ret
|
||||
SlotReelPosition3D ENDP
|
||||
|
||||
SlotExitMouse3D PROC
|
||||
cmp mouseClick3D,0
|
||||
je slot_exit_mouse_done
|
||||
mov mouseClick3D,0
|
||||
cmp mouseY3D,3
|
||||
jb slot_exit_mouse_done
|
||||
cmp mouseY3D,17
|
||||
jae slot_exit_mouse_done
|
||||
cmp mouseX3D,252
|
||||
jb slot_exit_mouse_done
|
||||
cmp mouseX3D,312
|
||||
jae slot_exit_mouse_done
|
||||
call SlotEscape3D
|
||||
slot_exit_mouse_done:
|
||||
ret
|
||||
SlotExitMouse3D ENDP
|
||||
|
||||
HandleNativeSlots3D PROC uses ebx
|
||||
cmp slotSpinState,SLOT_SPIN
|
||||
jne slot_handle_idle
|
||||
; Process the header before settlement so the final spin tick cannot eat it.
|
||||
call SlotExitMouse3D
|
||||
mov eax,deltaTime3D
|
||||
cmp eax,250
|
||||
jbe @F
|
||||
mov eax,250
|
||||
@@:
|
||||
add slotSpinTimer,eax
|
||||
cmp slotSpinTimer,3000
|
||||
jb slot_handle_exit_mouse
|
||||
call SettleNativeSlots3D
|
||||
ret
|
||||
slot_handle_idle:
|
||||
mov eax,deltaTime3D
|
||||
add slotEffects3D,eax
|
||||
cmp slotEffects3D,2000
|
||||
jbe @F
|
||||
mov slotEffects3D,2000
|
||||
@@:
|
||||
cmp slotPaytable3D,0
|
||||
je slot_handle_controls
|
||||
invoke Pressed3D,0Dh
|
||||
test eax,eax
|
||||
jnz slot_close_paytable
|
||||
invoke Pressed3D,20h
|
||||
test eax,eax
|
||||
jnz slot_close_paytable
|
||||
invoke Pressed3D,50h
|
||||
test eax,eax
|
||||
jnz slot_close_paytable
|
||||
cmp mouseClick3D,0
|
||||
je slot_handle_done
|
||||
mov mouseClick3D,0
|
||||
cmp mouseY3D,202
|
||||
jb slot_handle_done
|
||||
cmp mouseY3D,220
|
||||
jae slot_handle_done
|
||||
cmp mouseX3D,112
|
||||
jb slot_handle_done
|
||||
cmp mouseX3D,208
|
||||
jae slot_handle_done
|
||||
slot_close_paytable:
|
||||
mov slotPaytable3D,0
|
||||
ret
|
||||
slot_handle_controls:
|
||||
cmp mouseClick3D,0
|
||||
je slot_handle_keys
|
||||
cmp mouseY3D,222
|
||||
jb slot_handle_keys
|
||||
cmp mouseY3D,238
|
||||
jae slot_handle_keys
|
||||
mov mouseClick3D,0
|
||||
mov eax,mouseX3D
|
||||
cmp eax,11
|
||||
jb slot_handle_keys
|
||||
cmp eax,29
|
||||
jb slot_bet_down
|
||||
cmp eax,35
|
||||
jb slot_handle_keys
|
||||
cmp eax,53
|
||||
jb slot_bet_up
|
||||
cmp eax,120
|
||||
jb slot_handle_keys
|
||||
cmp eax,190
|
||||
jb slot_handle_start
|
||||
cmp eax,202
|
||||
jb slot_handle_keys
|
||||
cmp eax,272
|
||||
jae slot_handle_keys
|
||||
mov slotPaytable3D,1
|
||||
ret
|
||||
slot_handle_keys:
|
||||
invoke Pressed3D,50h
|
||||
test eax,eax
|
||||
jz @F
|
||||
mov slotPaytable3D,1
|
||||
ret
|
||||
@@:
|
||||
invoke Pressed3D,57h
|
||||
test eax,eax
|
||||
jnz slot_bet_up
|
||||
invoke Pressed3D,26h
|
||||
test eax,eax
|
||||
jnz slot_bet_up
|
||||
invoke Pressed3D,53h
|
||||
test eax,eax
|
||||
jnz slot_bet_down
|
||||
invoke Pressed3D,28h
|
||||
test eax,eax
|
||||
jnz slot_bet_down
|
||||
invoke Pressed3D,20h
|
||||
test eax,eax
|
||||
jnz slot_handle_start
|
||||
invoke Pressed3D,0Dh
|
||||
test eax,eax
|
||||
jz slot_handle_exit_mouse
|
||||
slot_handle_start:
|
||||
call StartNativeSlots3D
|
||||
ret
|
||||
slot_bet_up:
|
||||
cmp slotBetIndex3D,6
|
||||
jae slot_handle_done
|
||||
inc slotBetIndex3D
|
||||
jmp slot_bet_changed
|
||||
slot_bet_down:
|
||||
cmp slotBetIndex3D,0
|
||||
je slot_handle_done
|
||||
dec slotBetIndex3D
|
||||
slot_bet_changed:
|
||||
mov ecx,slotBetIndex3D
|
||||
mov eax,slotBetValues3D[ecx*4]
|
||||
mov slotBet,eax
|
||||
mov slotError3D,0
|
||||
ret
|
||||
slot_handle_exit_mouse:
|
||||
call SlotExitMouse3D
|
||||
slot_handle_done:
|
||||
ret
|
||||
HandleNativeSlots3D ENDP
|
||||
|
||||
; Clip the 64x64 alpha-tested symbol to its own reel window, not the cabinet.
|
||||
DrawSlotSymbol3D PROC uses ebx esi edi symbol:DWORD,x:DWORD,y:DWORD
|
||||
local row:DWORD,lastRow:DWORD,source:DWORD
|
||||
cmp symbol,7
|
||||
ja slot_symbol_done
|
||||
mov eax,slotSymbolsPack3D.pixels
|
||||
test eax,eax
|
||||
jz slot_symbol_done
|
||||
mov ecx,symbol
|
||||
shl ecx,14
|
||||
add eax,ecx
|
||||
mov source,eax
|
||||
mov eax,y
|
||||
cmp eax,SLOT_TOP
|
||||
jge @F
|
||||
mov eax,SLOT_TOP
|
||||
@@:
|
||||
mov row,eax
|
||||
mov eax,y
|
||||
add eax,64
|
||||
cmp eax,SLOT_BOTTOM
|
||||
jle @F
|
||||
mov eax,SLOT_BOTTOM
|
||||
@@:
|
||||
mov lastRow,eax
|
||||
slot_symbol_row:
|
||||
mov eax,row
|
||||
cmp eax,lastRow
|
||||
jge slot_symbol_done
|
||||
mov ecx,eax
|
||||
sub ecx,y
|
||||
shl ecx,8
|
||||
mov esi,source
|
||||
add esi,ecx
|
||||
imul eax,640*4
|
||||
mov ecx,x
|
||||
lea edi,screenBuffer[eax+ecx*4]
|
||||
mov ecx,64
|
||||
slot_symbol_column:
|
||||
lodsd
|
||||
test eax,0FF000000h
|
||||
jz @F
|
||||
and eax,00FFFFFFh
|
||||
mov [edi],eax
|
||||
@@:
|
||||
add edi,4
|
||||
dec ecx
|
||||
jnz slot_symbol_column
|
||||
inc row
|
||||
jmp slot_symbol_row
|
||||
slot_symbol_done:
|
||||
ret
|
||||
DrawSlotSymbol3D ENDP
|
||||
|
||||
DrawSlotReel3D PROC uses ebx esi edi index:DWORD
|
||||
local offsetPx:DWORD,baseStop:DWORD,symbolY:DWORD,symbolX:DWORD
|
||||
invoke SlotReelPosition3D,index
|
||||
xor edx,edx
|
||||
mov ecx,64
|
||||
div ecx
|
||||
mov offsetPx,edx
|
||||
xor edx,edx
|
||||
mov ecx,20
|
||||
div ecx
|
||||
mov baseStop,edx
|
||||
mov ebx,index
|
||||
mov eax,slotWindows3D[ebx*4]
|
||||
add eax,12
|
||||
mov symbolX,eax
|
||||
mov eax,160
|
||||
sub eax,offsetPx
|
||||
sub eax,64
|
||||
mov symbolY,eax
|
||||
mov esi,baseStop
|
||||
add esi,19
|
||||
xor edi,edi
|
||||
slot_reel_symbol:
|
||||
mov eax,esi
|
||||
xor edx,edx
|
||||
mov ecx,20
|
||||
div ecx
|
||||
mov eax,slotStrip3D[edx*4]
|
||||
invoke DrawSlotSymbol3D,eax,symbolX,symbolY
|
||||
add symbolY,64
|
||||
inc esi
|
||||
inc edi
|
||||
cmp edi,4
|
||||
jb slot_reel_symbol
|
||||
ret
|
||||
DrawSlotReel3D ENDP
|
||||
|
||||
RenderNativeSlots3D PROC uses ebx esi edi
|
||||
; The validated cabinet is opaque and already framebuffer-sized.
|
||||
mov esi,slotCabinetPack3D.pixels
|
||||
test esi,esi
|
||||
jz slot_render_done
|
||||
lea edi,screenBuffer
|
||||
mov ecx,SCREEN_SIZE
|
||||
rep movsd
|
||||
xor esi,esi
|
||||
slot_render_reels:
|
||||
invoke DrawSlotReel3D,esi
|
||||
inc esi
|
||||
cmp esi,3
|
||||
jb slot_render_reels
|
||||
; The payline is fixed at the center of the three physical drums.
|
||||
invoke DrawBox,86,94,4,3,00E9CE71h
|
||||
invoke DrawBox,232,94,4,3,00E9CE71h
|
||||
cmp slotSpinState,SLOT_RESULT
|
||||
jne slot_render_header
|
||||
cmp slotWinAmount,0
|
||||
je slot_render_header
|
||||
mov eax,slotEffects3D
|
||||
xor edx,edx
|
||||
mov ecx,200
|
||||
div ecx
|
||||
test eax,1
|
||||
jnz slot_render_header
|
||||
invoke DrawBox,90,94,142,1,00E9CE71h
|
||||
slot_render_header:
|
||||
invoke DrawBox,0,0,320,19,00151D20h
|
||||
invoke DrawString8x8,8,6,OFFSET slotTitle3D,00E8D7ADh
|
||||
invoke DrawString8x8,54,6,OFFSET textBank3D,00A8DDB9h
|
||||
invoke FormatNumber,bankroll,OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,103,6,OFFSET hudNumBuffer,00F4F3E8h
|
||||
invoke DrawBoxBorder,252,3,60,14,002C3637h,00687672h,1
|
||||
invoke DrawString8x8,258,6,OFFSET cardExitButton3D,00E9D8B0h
|
||||
mov ebx,OFFSET slotReadyText3D
|
||||
cmp slotSpinState,SLOT_SPIN
|
||||
jne @F
|
||||
mov ebx,OFFSET slotRollingText3D
|
||||
@@:
|
||||
cmp slotSpinState,SLOT_RESULT
|
||||
jne @F
|
||||
mov ebx,OFFSET slotLoseText3D
|
||||
cmp slotWinAmount,0
|
||||
je @F
|
||||
mov ebx,OFFSET slotWinText3D
|
||||
@@:
|
||||
cmp slotError3D,0
|
||||
je @F
|
||||
mov ebx,OFFSET slotNoMoney3D
|
||||
@@:
|
||||
cmp slotLeaveAfter3D,0
|
||||
je @F
|
||||
mov ebx,OFFSET slotExitText3D
|
||||
@@:
|
||||
; Keep the message on the generated inset plate, with fixed-size numerals.
|
||||
invoke DrawBox,98,147,126,12,00151D20h
|
||||
invoke DrawString8x8,104,149,ebx,00E8D7ADh
|
||||
cmp slotSpinState,SLOT_RESULT
|
||||
jne slot_render_controls
|
||||
cmp slotWinAmount,0
|
||||
je 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 FormatNumber,slotBet,OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,83,207,OFFSET hudNumBuffer,00F4F3E8h
|
||||
mov ebx,1
|
||||
cmp slotSpinState,SLOT_SPIN
|
||||
jne @F
|
||||
xor ebx,ebx
|
||||
@@:
|
||||
mov edi,006D7470h
|
||||
test ebx,ebx
|
||||
jz @F
|
||||
mov edi,00EEE5CDh
|
||||
@@:
|
||||
invoke DrawBoxBorder,11,222,18,16,0025372Ch,edi,1
|
||||
invoke DrawBoxBorder,35,222,18,16,0025372Ch,edi,1
|
||||
invoke DrawString8x8,16,226,OFFSET tableMinusText3D,edi
|
||||
invoke DrawString8x8,40,226,OFFSET tablePlusText3D,edi
|
||||
invoke DrawTableButton3D,120,OFFSET slotSpinText3D,ebx
|
||||
invoke DrawTableButton3D,202,OFFSET slotPayText3D,ebx
|
||||
cmp slotPaytable3D,0
|
||||
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
|
||||
xor esi,esi
|
||||
slot_render_pay_row:
|
||||
mov edi,esi
|
||||
imul edi,14
|
||||
add edi,66
|
||||
mov eax,slotSymbolNames3D[esi*4]
|
||||
invoke DrawString8x8,62,edi,eax,00F4F3E8h
|
||||
invoke FormatNumber,slotTriple3D[esi*4],OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,212,edi,OFFSET strMultiplier3D,00E8D7ADh
|
||||
invoke DrawString8x8,220,edi,OFFSET hudNumBuffer,00E8D7ADh
|
||||
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 DrawBoxBorder,112,204,96,15,003B6C59h,00E9D8B0h,1
|
||||
invoke DrawString8x8,128,207,OFFSET slotCloseText3D,00E9D8B0h
|
||||
slot_render_done:
|
||||
ret
|
||||
RenderNativeSlots3D ENDP
|
||||
69
src_graphics/native_slots_data.inc
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
; One fixed 20-stop strip per reel. Only the middle payline pays.
|
||||
SLOT_READY equ 0
|
||||
SLOT_SPIN equ 1
|
||||
SLOT_RESULT equ 2
|
||||
SLOT_CELL equ 64
|
||||
SLOT_TOP equ 124
|
||||
SLOT_BOTTOM equ 260
|
||||
InitNativeSlots3D PROTO
|
||||
FreeNativeSlots3D PROTO
|
||||
StartNativeSlots3D PROTO
|
||||
HandleNativeSlots3D PROTO
|
||||
RenderNativeSlots3D PROTO
|
||||
SlotMultiplier3D PROTO :DWORD,:DWORD,:DWORD
|
||||
SettleNativeSlots3D PROTO
|
||||
SlotEscape3D PROTO
|
||||
SlotExitMouse3D PROTO
|
||||
SlotReelPosition3D PROTO :DWORD
|
||||
DrawSlotReel3D PROTO :DWORD
|
||||
DrawSlotSymbol3D PROTO :DWORD,:DWORD,:DWORD
|
||||
.data
|
||||
slotCabinetPack3D AnimPack3D <>
|
||||
slotSymbolsPack3D AnimPack3D <>
|
||||
slotCabinetPath3D db "assets\animations\slots\cabinet-v1.bin",0
|
||||
slotSymbolsPath3D db "assets\animations\slots\symbols-v1.bin",0
|
||||
slotStrip3D dd 1,2,5,3,1,4,2,5,1,3,0,2,1,4,5,3,6,2,1,7
|
||||
slotTriple3D dd 100,8,10,15,25,12,60,150
|
||||
slotDurations3D dd 1800,2400,3000
|
||||
slotCycles3D dd 80,100,120
|
||||
slotWindows3D dd 180,278,376
|
||||
slotStops3D dd 0,6,12
|
||||
slotStartStops3D dd 0,6,12
|
||||
slotTravel3D dd 3 dup(0)
|
||||
slotTargets3D dd 3 dup(0)
|
||||
slotBetValues3D dd 10,50,100,500,1000,5000,10000
|
||||
slotBetIndex3D dd 1
|
||||
slotStake3D dd 0
|
||||
slotLeaveAfter3D dd 0
|
||||
slotPaytable3D dd 0
|
||||
slotError3D dd 0
|
||||
slotEffects3D dd 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
|
||||
slotPayTitle3D db 210,192,193,203,200,214,192,32,194,219,207,203,192,210,0
|
||||
slotCloseText3D db 199,192,202,208,219,210,220,0
|
||||
slotBetText3D db 209,210,192,194,202,192,32,36,0
|
||||
slotWinText3D db 194,219,207,203,192,210,192,0
|
||||
slotReadyText3D db 195,206,210,206,194,0
|
||||
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
|
||||
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
|
||||
slotPayNote3D db 209,210,192,194,202,192,32,194,202,203,222,215,197,205,192,32,194,32,194,219,207,203,192,210,211,0
|
||||
slotSymbol0Name3D db "7",0
|
||||
slotSymbol1Name3D db 194,200,216,205,223,0
|
||||
slotSymbol2Name3D db 203,200,204,206,205,0
|
||||
slotSymbol3Name3D db 202,206,203,206,202,206,203,0
|
||||
slotSymbol4Name3D db "BAR",0
|
||||
slotSymbol5Name3D db 194,200,205,206,195,208,192,196,0
|
||||
slotSymbol6Name3D db 192,203,204,192,199,0
|
||||
slotSymbol7Name3D db 202,206,208,206,205,192,0
|
||||
slotSymbolNames3D dd OFFSET slotSymbol0Name3D,OFFSET slotSymbol1Name3D
|
||||
dd OFFSET slotSymbol2Name3D,OFFSET slotSymbol3Name3D,OFFSET slotSymbol4Name3D
|
||||
dd OFFSET slotSymbol5Name3D,OFFSET slotSymbol6Name3D,OFFSET slotSymbol7Name3D
|
||||
.code
|
||||
|
|
@ -7,12 +7,14 @@ InitNativeWheel3D PROC uses edi
|
|||
mov wheelStake3D, 0
|
||||
mov wheelReturn3D, 0
|
||||
mov wheelTime3D, 0
|
||||
mov wheelExitQueued3D, 0
|
||||
call LoadNativeWheelArt3D
|
||||
ret
|
||||
InitNativeWheel3D ENDP
|
||||
|
||||
WheelAddBet3D PROC index:DWORD
|
||||
cmp roulState, 1
|
||||
je wheel_add_done
|
||||
cmp roulState, 0
|
||||
jne wheel_add_done
|
||||
mov ecx, index
|
||||
cmp ecx, 48
|
||||
ja wheel_add_done
|
||||
|
|
@ -136,6 +138,21 @@ wheel_settle_done:
|
|||
WheelSettle3D ENDP
|
||||
|
||||
HandleNativeWheel3D PROC uses ebx esi edi
|
||||
cmp mouseClick3D,0
|
||||
je wheel_header_done
|
||||
cmp mouseY3D,3
|
||||
jb wheel_header_done
|
||||
cmp mouseY3D,17
|
||||
jae wheel_header_done
|
||||
cmp mouseX3D,252
|
||||
jb wheel_header_done
|
||||
cmp mouseX3D,312
|
||||
jae wheel_header_done
|
||||
mov mouseClick3D,0
|
||||
call WheelEscape3D
|
||||
cmp engineMode,MODE_WALK
|
||||
je wheel_handle_done
|
||||
wheel_header_done:
|
||||
cmp roulState, 1
|
||||
jne wheel_draft_input
|
||||
mov eax, deltaTime3D
|
||||
|
|
@ -143,17 +160,34 @@ HandleNativeWheel3D PROC uses ebx esi edi
|
|||
cmp wheelTime3D, 4200
|
||||
jb wheel_handle_done
|
||||
call WheelSettle3D
|
||||
cmp wheelExitQueued3D,0
|
||||
je wheel_handle_done
|
||||
call WheelEscape3D
|
||||
ret
|
||||
wheel_draft_input:
|
||||
cmp roulState, 2
|
||||
jne @F
|
||||
; Keep last winnings visible, but a new spin begins with an empty layout.
|
||||
lea edi, wheelBets3D
|
||||
xor eax, eax
|
||||
mov ecx, 49
|
||||
rep stosd
|
||||
mov wheelStake3D, 0
|
||||
mov roulState, 0
|
||||
; Keep the landed ball and payout visible until an explicit next-round command.
|
||||
invoke Pressed3D,20h
|
||||
test eax,eax
|
||||
jnz wheel_next_layout
|
||||
invoke Pressed3D,0Dh
|
||||
test eax,eax
|
||||
jnz wheel_next_layout
|
||||
cmp mouseClick3D,0
|
||||
je wheel_handle_done
|
||||
cmp mouseY3D,219
|
||||
jb wheel_handle_done
|
||||
cmp mouseY3D,237
|
||||
jae wheel_handle_done
|
||||
cmp mouseX3D,120
|
||||
jb wheel_handle_done
|
||||
cmp mouseX3D,200
|
||||
jae wheel_handle_done
|
||||
wheel_next_layout:
|
||||
mov mouseClick3D,0
|
||||
call InitNativeWheel3D
|
||||
ret
|
||||
@@:
|
||||
invoke Pressed3D, 57h
|
||||
test eax, eax
|
||||
|
|
@ -199,6 +233,8 @@ wheel_mouse_number:
|
|||
sub eax, 123
|
||||
xor edx, edx
|
||||
div ecx
|
||||
neg eax
|
||||
add eax,2
|
||||
add eax, ebx
|
||||
inc eax
|
||||
invoke WheelAddBet3D, eax
|
||||
|
|
@ -231,13 +267,43 @@ wheel_button:
|
|||
jb wheel_spin_input
|
||||
cmp mouseY3D, 121
|
||||
jae wheel_spin_input
|
||||
cmp mouseX3D,145
|
||||
jb wheel_spin_input
|
||||
cmp mouseX3D,159
|
||||
jb wheel_mouse_more
|
||||
cmp mouseX3D,162
|
||||
jb wheel_spin_input
|
||||
cmp mouseX3D,176
|
||||
jb wheel_mouse_less
|
||||
cmp mouseX3D,180
|
||||
jb wheel_spin_input
|
||||
cmp mouseX3D,226
|
||||
jb wheel_mouse_clear
|
||||
cmp mouseX3D, 230
|
||||
jb wheel_spin_input
|
||||
cmp mouseX3D,300
|
||||
jae wheel_spin_input
|
||||
mov pressedKeys3D[20h], 1
|
||||
jmp wheel_spin_input
|
||||
wheel_mouse_more:
|
||||
cmp wheelChip3D,1000000
|
||||
jae wheel_handle_done
|
||||
add wheelChip3D,50
|
||||
ret
|
||||
wheel_mouse_less:
|
||||
cmp wheelChip3D,50
|
||||
jbe wheel_handle_done
|
||||
sub wheelChip3D,50
|
||||
ret
|
||||
wheel_mouse_clear:
|
||||
call InitNativeWheel3D
|
||||
ret
|
||||
wheel_spin_input:
|
||||
invoke Pressed3D, 20h
|
||||
test eax, eax
|
||||
jz wheel_handle_done
|
||||
cmp wheelArtReady3D,1
|
||||
jne wheel_handle_done
|
||||
mov eax, wheelStake3D
|
||||
test eax, eax
|
||||
jz wheel_handle_done
|
||||
|
|
@ -256,51 +322,28 @@ HandleNativeWheel3D ENDP
|
|||
|
||||
RenderNativeWheel3D PROC uses ebx esi edi
|
||||
local x:DWORD,y:DWORD,ink:DWORD,angle:DWORD
|
||||
invoke DrawBox,0,0,320,240,00142D22h
|
||||
call RenderWheelScene3D
|
||||
cmp wheelArtReady3D,1
|
||||
jne wheel_render_missing
|
||||
invoke DrawBox,0,0,320,20,0014191Dh
|
||||
invoke DrawString8x8,16,12,OFFSET wheelTitle3D,00E5D29Eh
|
||||
invoke DrawNumber,206,12,bankroll,00F4E7C8h
|
||||
invoke DrawCircle,160,66,42,00886E42h
|
||||
invoke DrawCircle,160,66,38,00232C29h
|
||||
invoke DrawCircle,160,66,24,005E422Bh
|
||||
xor esi, esi
|
||||
wheel_result_slot:
|
||||
mov eax, wheelOrder3D[esi*4]
|
||||
cmp eax, wheelResult3D
|
||||
je wheel_slot_found
|
||||
inc esi
|
||||
cmp esi, 37
|
||||
jb wheel_result_slot
|
||||
wheel_slot_found:
|
||||
mov eax, esi
|
||||
imul eax, 512
|
||||
xor edx, edx
|
||||
mov ecx, 37
|
||||
div ecx
|
||||
cmp roulState, 1
|
||||
jne @F
|
||||
mov ecx, 4200
|
||||
sub ecx, wheelTime3D
|
||||
imul ecx, 3
|
||||
add eax, ecx
|
||||
@@:
|
||||
and eax, 511
|
||||
mov angle, eax
|
||||
mov ebx, tableCos[eax*4]
|
||||
imul ebx, 34
|
||||
sar ebx, 16
|
||||
add ebx, 160
|
||||
mov edx, tableSin[eax*4]
|
||||
imul edx, 34
|
||||
sar edx, 16
|
||||
add edx, 66
|
||||
invoke DrawCircle,ebx,edx,3,00F4EAD8h
|
||||
invoke DrawNumber,153,60,wheelResult3D,00FFFFFFh
|
||||
invoke DrawBoxBorder,252,3,60,14,00252D2Ah,0086754Eh,1
|
||||
invoke DrawString8x8,266,6,OFFSET wheelExitText3D,00E5D29Eh
|
||||
cmp roulState,1
|
||||
je wheel_render_spin_hud
|
||||
cmp roulState,2
|
||||
je wheel_render_result_hud
|
||||
invoke DrawBox,8,101,304,123,00142D22h
|
||||
invoke DrawString8x8,18,104,OFFSET wheelAmountText3D,00DEDACAh
|
||||
invoke DrawNumber,74,104,wheelChip3D,00FFFFFFh
|
||||
invoke DrawString8x8,116,104,OFFSET wheelStakedText3D,00DEDACAh
|
||||
invoke DrawNumber,180,104,wheelStake3D,00FFFFFFh
|
||||
invoke DrawNumber,78,104,wheelChip3D,00FFFFFFh
|
||||
invoke DrawBoxBorder,145,104,14,16,003B3024h,00C6AA66h,1
|
||||
invoke DrawString8x8,148,108,OFFSET wheelPlusText3D,00FFFFFFh
|
||||
invoke DrawBoxBorder,162,104,14,16,003B3024h,00C6AA66h,1
|
||||
invoke DrawString8x8,165,108,OFFSET wheelMinusText3D,00FFFFFFh
|
||||
invoke DrawBoxBorder,180,104,46,16,003B3024h,00C6AA66h,1
|
||||
invoke DrawString8x8,183,108,OFFSET wheelClear3D,00FFFFFFh
|
||||
invoke DrawBoxBorder,230,104,70,16,00423929h,00C6AA66h,1
|
||||
invoke DrawString8x8,250,108,OFFSET wheelSpin3D,00FFFFFFh
|
||||
invoke DrawString8x8,237,108,OFFSET wheelSpin3D,00FFFFFFh
|
||||
invoke DrawBoxBorder,24,123,34,60,00174A33h,009C9A76h,1
|
||||
invoke DrawNumber,36,147,0,00FFFFFFh
|
||||
cmp wheelBets3D, 0
|
||||
|
|
@ -317,6 +360,8 @@ wheel_render_numbers:
|
|||
imul eax, 20
|
||||
add eax, 60
|
||||
mov x, eax
|
||||
neg edx
|
||||
add edx,2
|
||||
imul edx, 20
|
||||
add edx, 123
|
||||
mov y, edx
|
||||
|
|
@ -368,11 +413,489 @@ wheel_render_outside:
|
|||
inc esi
|
||||
cmp esi, 12
|
||||
jb wheel_render_outside
|
||||
invoke DrawString8x8,24,228,OFFSET wheelPaidText3D,00D3C08Fh
|
||||
invoke DrawNumber,88,228,wheelReturn3D,00FFFFFFh
|
||||
invoke DrawString8x8,24,228,OFFSET wheelStakedText3D,00D3C08Fh
|
||||
invoke DrawNumber,88,228,wheelStake3D,00FFFFFFh
|
||||
invoke DrawNumber,206,26,bankroll,00F4E7C8h
|
||||
ret
|
||||
wheel_render_spin_hud:
|
||||
invoke DrawBox,0,220,320,20,0014191Dh
|
||||
mov eax,OFFSET wheelSpinningText3D
|
||||
cmp wheelExitQueued3D,0
|
||||
je @F
|
||||
mov eax,OFFSET wheelLeavingText3D
|
||||
@@:
|
||||
invoke DrawString8x8,76,226,eax,00E5D29Eh
|
||||
ret
|
||||
wheel_render_result_hud:
|
||||
invoke DrawBox,0,219,320,21,0014191Dh
|
||||
invoke DrawString8x8,8,225,OFFSET wheelResultText3D,00E5D29Eh
|
||||
invoke DrawNumber,61,225,wheelResult3D,00FFFFFFh
|
||||
invoke DrawBoxBorder,120,220,80,17,003B3024h,00BA9955h,1
|
||||
invoke DrawString8x8,144,225,OFFSET wheelBetView3D,00FFFFFFh
|
||||
invoke DrawString8x8,208,223,OFFSET wheelPaidText3D,00E5D29Eh
|
||||
invoke DrawNumber,208,232,wheelReturn3D,00FFFFFFh
|
||||
ret
|
||||
wheel_render_missing:
|
||||
invoke DrawBox,0,0,320,240,0014191Dh
|
||||
invoke DrawString8x8,64,108,OFFSET wheelMissingArt3D,00E5D29Eh
|
||||
ret
|
||||
RenderNativeWheel3D ENDP
|
||||
|
||||
LoadNativeWheelArt3D PROC
|
||||
cmp wheelArtReady3D,1
|
||||
je wheel_art_loaded
|
||||
invoke LoadAnimPack3D,OFFSET wheelTableArt3D,OFFSET wheelTablePath3D
|
||||
invoke LoadAnimPack3D,OFFSET wheelCloseArt3D,OFFSET wheelClosePath3D
|
||||
invoke LoadAnimPack3D,OFFSET wheelRotorArt3D,OFFSET wheelRotorPath3D
|
||||
invoke ValidateCityPack3D,OFFSET wheelTableArt3D,640,480,1
|
||||
invoke ValidateCityPack3D,OFFSET wheelCloseArt3D,640,480,1
|
||||
invoke ValidateCityPack3D,OFFSET wheelRotorArt3D,480,480,1
|
||||
cmp wheelTableArt3D.pixels,0
|
||||
je wheel_art_failed
|
||||
cmp wheelCloseArt3D.pixels,0
|
||||
je wheel_art_failed
|
||||
cmp wheelRotorArt3D.pixels,0
|
||||
je wheel_art_failed
|
||||
mov wheelArtReady3D,1
|
||||
wheel_art_loaded:
|
||||
mov eax,1
|
||||
ret
|
||||
wheel_art_failed:
|
||||
call FreeNativeWheelArt3D
|
||||
xor eax,eax
|
||||
ret
|
||||
LoadNativeWheelArt3D ENDP
|
||||
|
||||
FreeNativeWheelArt3D PROC
|
||||
invoke FreeAnimPack3D,OFFSET wheelTableArt3D
|
||||
invoke FreeAnimPack3D,OFFSET wheelCloseArt3D
|
||||
invoke FreeAnimPack3D,OFFSET wheelRotorArt3D
|
||||
mov wheelArtReady3D,0
|
||||
ret
|
||||
FreeNativeWheelArt3D ENDP
|
||||
|
||||
WheelEscape3D PROC
|
||||
mov paused3D,0
|
||||
cmp roulState,1
|
||||
jne wheel_leave_hall
|
||||
mov wheelExitQueued3D,1
|
||||
call ClearKeys3D
|
||||
ret
|
||||
wheel_leave_hall:
|
||||
mov wheelExitQueued3D,0
|
||||
mov engineMode,MODE_WALK
|
||||
call ClearKeys3D
|
||||
invoke PlayCasinoSound3D,0,0,0
|
||||
ret
|
||||
WheelEscape3D ENDP
|
||||
|
||||
; Integer quadratic easing, preserving the 64-bit product until division.
|
||||
WheelTravel3D PROC uses ebx timeMs:DWORD,durationMs:DWORD,total:DWORD
|
||||
mov eax,timeMs
|
||||
cmp eax,durationMs
|
||||
jae wheel_travel_end
|
||||
mov eax,durationMs
|
||||
sub eax,timeMs
|
||||
mul eax
|
||||
mul total
|
||||
mov ebx,durationMs
|
||||
imul ebx,ebx
|
||||
div ebx
|
||||
neg eax
|
||||
add eax,total
|
||||
ret
|
||||
wheel_travel_end:
|
||||
mov eax,total
|
||||
ret
|
||||
WheelTravel3D ENDP
|
||||
|
||||
; Rotate the exact numbered rotor by inverse sampling, then project onto the bowl ellipse.
|
||||
; Physical framebuffer coordinates; rendering cannot change the selected outcome or bank.
|
||||
DrawNativeWheelDisc3D PROC uses ebx esi edi centerX:DWORD,centerY:DWORD,radiusX:DWORD,radiusY:DWORD,rotorAngle:DWORD
|
||||
local row:DWORD,column:DWORD,minX:DWORD,maxX:DWORD,maxY:DWORD
|
||||
local circleX:DWORD,circleY:DWORD,cosine:DWORD,sine:DWORD,sourceX:DWORD
|
||||
mov eax,rotorAngle
|
||||
and eax,511
|
||||
mov ecx,tableCos[eax*4]
|
||||
mov cosine,ecx
|
||||
mov ecx,tableSin[eax*4]
|
||||
mov sine,ecx
|
||||
mov eax,centerX
|
||||
sub eax,radiusX
|
||||
jns @F
|
||||
xor eax,eax
|
||||
@@:
|
||||
mov minX,eax
|
||||
mov eax,centerX
|
||||
add eax,radiusX
|
||||
cmp eax,SCREEN_W
|
||||
jl @F
|
||||
mov eax,SCREEN_W-1
|
||||
@@:
|
||||
mov maxX,eax
|
||||
mov eax,centerY
|
||||
add eax,radiusY
|
||||
cmp eax,SCREEN_H
|
||||
jl @F
|
||||
mov eax,SCREEN_H-1
|
||||
@@:
|
||||
mov maxY,eax
|
||||
mov eax,centerY
|
||||
sub eax,radiusY
|
||||
jns @F
|
||||
xor eax,eax
|
||||
@@:
|
||||
mov row,eax
|
||||
wheel_disc_row:
|
||||
mov eax,row
|
||||
sub eax,centerY
|
||||
imul eax,224
|
||||
cdq
|
||||
idiv radiusY
|
||||
mov circleY,eax
|
||||
mov eax,row
|
||||
imul eax,SCREEN_W*4
|
||||
add eax,OFFSET screenBuffer
|
||||
mov ecx,minX
|
||||
lea edi,[eax+ecx*4]
|
||||
mov column,ecx
|
||||
wheel_disc_pixel:
|
||||
mov eax,column
|
||||
sub eax,centerX
|
||||
imul eax,224
|
||||
cdq
|
||||
idiv radiusX
|
||||
mov circleX,eax
|
||||
imul eax,eax
|
||||
mov ecx,circleY
|
||||
imul ecx,ecx
|
||||
add eax,ecx
|
||||
cmp eax,224*224
|
||||
ja wheel_disc_next
|
||||
mov eax,circleX
|
||||
imul eax,cosine
|
||||
mov ecx,circleY
|
||||
imul ecx,sine
|
||||
add eax,ecx
|
||||
sar eax,16
|
||||
add eax,240
|
||||
mov sourceX,eax
|
||||
mov eax,circleY
|
||||
imul eax,cosine
|
||||
mov ecx,circleX
|
||||
imul ecx,sine
|
||||
sub eax,ecx
|
||||
sar eax,16
|
||||
add eax,240
|
||||
imul eax,480
|
||||
add eax,sourceX
|
||||
mov esi,wheelRotorArt3D.pixels
|
||||
mov eax,[esi+eax*4]
|
||||
cmp eax,80000000h
|
||||
jb wheel_disc_next
|
||||
and eax,00FFFFFFh
|
||||
mov [edi],eax
|
||||
wheel_disc_next:
|
||||
add edi,4
|
||||
inc column
|
||||
mov eax,column
|
||||
cmp eax,maxX
|
||||
jle wheel_disc_pixel
|
||||
inc row
|
||||
mov eax,row
|
||||
cmp eax,maxY
|
||||
jle wheel_disc_row
|
||||
ret
|
||||
DrawNativeWheelDisc3D ENDP
|
||||
|
||||
RenderWheelScene3D PROC uses ebx esi edi
|
||||
local centerX:DWORD,centerY:DWORD,radiusX:DWORD,radiusY:DWORD
|
||||
local cameraPhase:DWORD,ballRadius:DWORD,ballAngle:DWORD,oldOpacity:DWORD
|
||||
cmp wheelArtReady3D,1
|
||||
jne wheel_scene_done
|
||||
mov esi,wheelTableArt3D.pixels
|
||||
lea edi,screenBuffer
|
||||
mov ecx,SCREEN_SIZE
|
||||
rep movsd
|
||||
mov centerX,206
|
||||
mov centerY,170
|
||||
mov radiusX,142
|
||||
mov radiusY,46
|
||||
mov cameraPhase,0
|
||||
cmp roulState,0
|
||||
je wheel_scene_geometry
|
||||
mov cameraPhase,FP_1
|
||||
cmp roulState,1
|
||||
jne wheel_scene_close
|
||||
invoke CityEase3D,wheelTime3D,600
|
||||
mov cameraPhase,eax
|
||||
wheel_scene_close:
|
||||
mov eax,animOpacity3D
|
||||
mov oldOpacity,eax
|
||||
mov eax,cameraPhase
|
||||
imul eax,255
|
||||
shr eax,16
|
||||
mov animOpacity3D,eax
|
||||
invoke DrawAnimSprite3D,OFFSET wheelCloseArt3D,0,0,0,640,480
|
||||
mov eax,oldOpacity
|
||||
mov animOpacity3D,eax
|
||||
mov eax,cameraPhase
|
||||
imul eax,114
|
||||
shr eax,16
|
||||
add centerX,eax
|
||||
mov eax,cameraPhase
|
||||
imul eax,108
|
||||
shr eax,16
|
||||
add centerY,eax
|
||||
mov eax,cameraPhase
|
||||
imul eax,63
|
||||
shr eax,16
|
||||
add radiusX,eax
|
||||
mov eax,cameraPhase
|
||||
imul eax,42
|
||||
shr eax,16
|
||||
add radiusY,eax
|
||||
wheel_scene_geometry:
|
||||
mov wheelRotorAngle3D,0
|
||||
cmp roulState,1
|
||||
jne @F
|
||||
invoke WheelTravel3D,wheelTime3D,4200,4096
|
||||
and eax,511
|
||||
mov wheelRotorAngle3D,eax
|
||||
@@:
|
||||
invoke DrawNativeWheelDisc3D,centerX,centerY,radiusX,radiusY,wheelRotorAngle3D
|
||||
cmp roulState,2
|
||||
je @F
|
||||
invoke DrawWheelLabels3D,centerX,centerY,radiusX,radiusY,wheelRotorAngle3D
|
||||
@@:
|
||||
cmp roulState,0
|
||||
je wheel_scene_done
|
||||
xor esi,esi
|
||||
wheel_find_pocket:
|
||||
mov eax,wheelOrder3D[esi*4]
|
||||
cmp eax,wheelResult3D
|
||||
je wheel_found_pocket
|
||||
inc esi
|
||||
cmp esi,37
|
||||
jb wheel_find_pocket
|
||||
jmp wheel_scene_done
|
||||
wheel_found_pocket:
|
||||
mov wheelResultSlot3D,esi
|
||||
imul eax,esi,512
|
||||
xor edx,edx
|
||||
mov ecx,37
|
||||
div ecx
|
||||
add eax,wheelRotorAngle3D
|
||||
mov ballAngle,eax
|
||||
mov ballRadius,170
|
||||
cmp roulState,1
|
||||
jne wheel_ball_place
|
||||
invoke WheelTravel3D,wheelTime3D,4200,6144
|
||||
sub eax,6144
|
||||
add ballAngle,eax
|
||||
mov ballRadius,216
|
||||
cmp wheelTime3D,2600
|
||||
jb wheel_ball_place
|
||||
mov eax,wheelTime3D
|
||||
sub eax,2600
|
||||
cmp eax,1600
|
||||
jbe @F
|
||||
mov eax,1600
|
||||
@@:
|
||||
imul eax,46
|
||||
xor edx,edx
|
||||
mov ecx,1600
|
||||
div ecx
|
||||
sub ballRadius,eax
|
||||
wheel_ball_place:
|
||||
mov eax,ballAngle
|
||||
and eax,511
|
||||
mov wheelBallAngle3D,eax
|
||||
mov ebx,tableCos[eax*4]
|
||||
imul ebx,ballRadius
|
||||
sar ebx,16
|
||||
imul ebx,radiusX
|
||||
mov eax,ebx
|
||||
cdq
|
||||
mov ecx,224
|
||||
idiv ecx
|
||||
add eax,centerX
|
||||
mov wheelBallX3D,eax
|
||||
mov eax,wheelBallAngle3D
|
||||
mov ebx,tableSin[eax*4]
|
||||
imul ebx,ballRadius
|
||||
sar ebx,16
|
||||
imul ebx,radiusY
|
||||
mov eax,ebx
|
||||
cdq
|
||||
idiv ecx
|
||||
add eax,centerY
|
||||
mov wheelBallY3D,eax
|
||||
sar eax,1
|
||||
mov edi,eax
|
||||
mov ebx,wheelBallX3D
|
||||
sar ebx,1
|
||||
invoke DrawCircle,ebx,edi,3,003C3026h
|
||||
invoke DrawCircle,ebx,edi,2,00F6EFE0h
|
||||
cmp roulState,2
|
||||
jne wheel_scene_done
|
||||
invoke DrawWheelLabels3D,centerX,centerY,radiusX,radiusY,wheelRotorAngle3D
|
||||
invoke DrawBuckshotPanel3D,278,245,84,61,002D211Bh
|
||||
invoke DrawBuckshotText3D,296,253,OFFSET wheelLandedText3D,00E5D29Eh
|
||||
mov ecx,00F4E7C8h
|
||||
cmp wheelResult3D,0
|
||||
je @F
|
||||
mov eax,wheelResult3D
|
||||
bt wheelRedMask3D,eax
|
||||
jnc @F
|
||||
mov ecx,00FFB4ADh
|
||||
@@:
|
||||
invoke DrawWheelValue3D,320,268,wheelResult3D,6,ecx
|
||||
wheel_scene_done:
|
||||
ret
|
||||
RenderWheelScene3D 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 digit,9
|
||||
ja wheel_digit_done
|
||||
mov eax,digit
|
||||
imul eax,5
|
||||
lea esi,wheelDigitMasks3D[eax]
|
||||
mov row,0
|
||||
wheel_digit_row:
|
||||
mov eax,row
|
||||
movzx eax,BYTE PTR [esi+eax]
|
||||
mov bits,eax
|
||||
mov column,0
|
||||
wheel_digit_column:
|
||||
test bits,4
|
||||
jz wheel_digit_next
|
||||
mov eax,column
|
||||
imul eax,scale
|
||||
add eax,x
|
||||
mov px,eax
|
||||
mov eax,row
|
||||
imul eax,scale
|
||||
add eax,y
|
||||
mov py,eax
|
||||
invoke DrawBuckshotPanel3D,px,py,scale,scale,ink
|
||||
wheel_digit_next:
|
||||
shl bits,1
|
||||
inc column
|
||||
cmp column,3
|
||||
jb wheel_digit_column
|
||||
inc row
|
||||
cmp row,5
|
||||
jb wheel_digit_row
|
||||
wheel_digit_done:
|
||||
ret
|
||||
DrawWheelDigit3D ENDP
|
||||
|
||||
DrawWheelValue3D PROC uses ebx centerX:DWORD,y:DWORD,value:DWORD,scale:DWORD,ink:DWORD
|
||||
local x:DWORD,ones:DWORD
|
||||
mov eax,scale
|
||||
imul eax,3
|
||||
cmp value,10
|
||||
jb @F
|
||||
mov eax,scale
|
||||
imul eax,7
|
||||
@@:
|
||||
shr eax,1
|
||||
neg eax
|
||||
add eax,centerX
|
||||
mov x,eax
|
||||
mov eax,value
|
||||
cmp eax,10
|
||||
jb wheel_value_single
|
||||
xor edx,edx
|
||||
mov ecx,10
|
||||
div ecx
|
||||
mov ones,edx
|
||||
invoke DrawWheelDigit3D,x,y,eax,scale,ink
|
||||
mov eax,scale
|
||||
shl eax,2
|
||||
add x,eax
|
||||
mov eax,ones
|
||||
wheel_value_single:
|
||||
invoke DrawWheelDigit3D,x,y,eax,scale,ink
|
||||
ret
|
||||
DrawWheelValue3D ENDP
|
||||
|
||||
DrawWheelLabels3D PROC uses ebx esi edi centerX:DWORD,centerY:DWORD,radiusX:DWORD,radiusY:DWORD,angle:DWORD
|
||||
local phase:DWORD,x:DWORD,y:DWORD
|
||||
mov wheelNumberScale3D,1
|
||||
cmp radiusY,80
|
||||
jb @F
|
||||
mov wheelNumberScale3D,2
|
||||
@@:
|
||||
xor esi,esi
|
||||
wheel_label_pocket:
|
||||
mov eax,esi
|
||||
imul eax,512
|
||||
xor edx,edx
|
||||
mov ecx,37
|
||||
div ecx
|
||||
add eax,angle
|
||||
and eax,511
|
||||
mov phase,eax
|
||||
mov eax,tableCos[eax*4]
|
||||
imul eax,195
|
||||
sar eax,16
|
||||
imul eax,radiusX
|
||||
cdq
|
||||
mov ecx,224
|
||||
idiv ecx
|
||||
add eax,centerX
|
||||
mov x,eax
|
||||
mov wheelNumberX3D[esi*4],eax
|
||||
mov eax,phase
|
||||
mov eax,tableSin[eax*4]
|
||||
imul eax,195
|
||||
sar eax,16
|
||||
imul eax,radiusY
|
||||
cdq
|
||||
idiv ecx
|
||||
add eax,centerY
|
||||
mov wheelNumberY3D[esi*4],eax
|
||||
mov ebx,wheelNumberScale3D
|
||||
imul ebx,5
|
||||
shr ebx,1
|
||||
sub eax,ebx
|
||||
mov y,eax
|
||||
invoke DrawWheelValue3D,x,y,wheelOrder3D[esi*4],wheelNumberScale3D,00FFF8DEh
|
||||
inc esi
|
||||
cmp esi,37
|
||||
jb wheel_label_pocket
|
||||
cmp roulState,2
|
||||
jne wheel_labels_done
|
||||
; Highlight the actual winning label after drawing the ball, preserving every digit.
|
||||
xor esi,esi
|
||||
wheel_label_find_result:
|
||||
mov eax,wheelOrder3D[esi*4]
|
||||
cmp eax,wheelResult3D
|
||||
je wheel_label_highlight
|
||||
inc esi
|
||||
cmp esi,37
|
||||
jb wheel_label_find_result
|
||||
jmp wheel_labels_done
|
||||
wheel_label_highlight:
|
||||
mov ebx,wheelNumberX3D[esi*4]
|
||||
mov edi,wheelNumberY3D[esi*4]
|
||||
sub ebx,9
|
||||
sub edi,6
|
||||
invoke DrawBuckshotPanel3D,ebx,edi,18,12,00E5C978h
|
||||
inc ebx
|
||||
inc edi
|
||||
invoke DrawBuckshotPanel3D,ebx,edi,16,10,00121916h
|
||||
mov eax,wheelNumberY3D[esi*4]
|
||||
sub eax,5
|
||||
invoke DrawWheelValue3D,wheelNumberX3D[esi*4],eax,wheelResult3D,2,00FFF8DEh
|
||||
wheel_labels_done:
|
||||
ret
|
||||
DrawWheelLabels3D ENDP
|
||||
|
||||
DrawNumber PROC x:DWORD,y:DWORD,value:DWORD,ink:DWORD
|
||||
invoke FormatNumber,value,OFFSET hudNumBuffer
|
||||
invoke DrawString8x8,x,y,OFFSET hudNumBuffer,ink
|
||||
|
|
|
|||
|
|
@ -3,7 +3,44 @@ HandleNativeWheel3D PROTO
|
|||
RenderNativeWheel3D PROTO
|
||||
WheelSettle3D PROTO
|
||||
WheelAddBet3D PROTO :DWORD
|
||||
LoadNativeWheelArt3D PROTO
|
||||
FreeNativeWheelArt3D PROTO
|
||||
WheelEscape3D PROTO
|
||||
WheelTravel3D PROTO :DWORD,:DWORD,:DWORD
|
||||
DrawNativeWheelDisc3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
RenderWheelScene3D PROTO
|
||||
DrawWheelDigit3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
DrawWheelValue3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
DrawWheelLabels3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||
.data
|
||||
wheelTableArt3D AnimPack3D <>
|
||||
wheelCloseArt3D AnimPack3D <>
|
||||
wheelRotorArt3D AnimPack3D <>
|
||||
wheelTablePath3D db "assets\animations\wheel\table-v1.bin",0
|
||||
wheelClosePath3D db "assets\animations\wheel\closeup-v1.bin",0
|
||||
wheelRotorPath3D db "assets\animations\wheel\rotor-v2.bin",0
|
||||
wheelArtReady3D dd 0
|
||||
wheelExitQueued3D dd 0
|
||||
wheelBallAngle3D dd 0
|
||||
wheelRotorAngle3D dd 0
|
||||
wheelResultSlot3D dd 0
|
||||
wheelBallX3D dd 0
|
||||
wheelBallY3D dd 0
|
||||
wheelNumberX3D dd 37 dup(0)
|
||||
wheelNumberY3D dd 37 dup(0)
|
||||
wheelNumberScale3D dd 1
|
||||
wheelDigitMasks3D db 7,5,5,5,7, 2,6,2,2,7, 7,1,7,4,7, 7,1,7,1,7
|
||||
db 5,5,7,1,1, 7,4,7,1,7, 7,4,7,5,7, 7,1,2,2,2
|
||||
db 7,5,7,5,7, 7,5,7,1,7
|
||||
wheelLandedText3D db 194,219,207,192,203,206,0
|
||||
wheelBetView3D db 209,210,192,194,202,200,0
|
||||
wheelExitText3D db 194,219,213,206,196,0
|
||||
wheelSpinningText3D db 209,210,192,194,202,200,32,199,192,202,208,219,210,219,0
|
||||
wheelLeavingText3D db 194,219,213,206,196,32,207,206,209,203,197,32,194,208,192,217,197,205,200,223,0
|
||||
wheelResultText3D db 215,200,209,203,206,0
|
||||
wheelMissingArt3D db 205,197,210,32,209,207,208,192,201,210,206,194,32,208,211,203,197,210,202,200,0
|
||||
wheelPlusText3D db "+",0
|
||||
wheelMinusText3D db "-",0
|
||||
wheelBets3D dd 49 dup(0)
|
||||
wheelStake3D dd 0
|
||||
wheelChip3D dd 50
|
||||
|
|
@ -14,22 +51,22 @@ wheelOrder3D dd 0,32,15,19,4,21,2,25,17,34,6,27,13,36,11,30,8,23,10,5,24,16,33,1
|
|||
wheelRedMask3D dd 4AAD52AAh,15h
|
||||
DrawNumber PROTO :DWORD,:DWORD,:DWORD,:DWORD
|
||||
wheelLabels3D dd OFFSET wheelRed3D,OFFSET wheelBlack3D,OFFSET wheelEven3D,OFFSET wheelOdd3D,OFFSET wheelLow3D,OFFSET wheelHigh3D,OFFSET wheelDozen13D,OFFSET wheelDozen23D,OFFSET wheelDozen33D,OFFSET wheelColumn13D,OFFSET wheelColumn23D,OFFSET wheelColumn33D
|
||||
wheelRed3D db "RED",0
|
||||
wheelBlack3D db "BLACK",0
|
||||
wheelEven3D db "EVEN",0
|
||||
wheelOdd3D db "ODD",0
|
||||
wheelRed3D db 202,208,192,209,205,0
|
||||
wheelBlack3D db 215,168,208,205,0
|
||||
wheelEven3D db 215,168,210,0
|
||||
wheelOdd3D db 205,197,215,168,210,0
|
||||
wheelLow3D db "1-18",0
|
||||
wheelHigh3D db "19-36",0
|
||||
wheelDozen13D db "1-12",0
|
||||
wheelDozen23D db "13-24",0
|
||||
wheelDozen33D db "25-36",0
|
||||
wheelColumn13D db "COL 1",0
|
||||
wheelColumn23D db "COL 2",0
|
||||
wheelColumn33D db "COL 3",0
|
||||
wheelTitle3D db "EUROPEAN ROULETTE",0
|
||||
wheelSpin3D db "SPIN",0
|
||||
wheelClear3D db "CLEAR",0
|
||||
wheelAmountText3D db "CHIP $",0
|
||||
wheelStakedText3D db "STAKE $",0
|
||||
wheelPaidText3D db "RETURN $",0
|
||||
wheelColumn13D db 208,223,196,32,49,0
|
||||
wheelColumn23D db 208,223,196,32,50,0
|
||||
wheelColumn33D db 208,223,196,32,51,0
|
||||
wheelTitle3D db 197,194,208,206,207,197,201,209,202,192,223,32,208,211,203,197,210,202,192,0
|
||||
wheelSpin3D db 202,208,211,210,200,210,220,0
|
||||
wheelClear3D db 209,193,208,206,209,0
|
||||
wheelAmountText3D db 212,200,216,202,192,32,36,0
|
||||
wheelStakedText3D db 209,210,192,194,202,192,32,36,0
|
||||
wheelPaidText3D db 194,219,207,203,192,210,192,0
|
||||
.code
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
; Events are processed on one thread. No secondary window or console is created.
|
||||
; Main and owned coin-detail windows are processed on the same thread; no CMD fallback.
|
||||
WindowEvents3D PROC uses ebx esi edi hwnd:DWORD, uMsg:DWORD, wp:DWORD, lp:DWORD
|
||||
cmp uMsg, 102h
|
||||
jne @F
|
||||
|
|
@ -379,6 +379,10 @@ Present3D ENDP
|
|||
|
||||
ToggleFullscreen3D PROC uses ebx esi edi
|
||||
local visibleStyle:DWORD
|
||||
local detailOpen:DWORD
|
||||
mov eax,coinDetailWnd3D
|
||||
mov detailOpen,eax
|
||||
call CloseCoinDetail3D
|
||||
invoke GetWindowLongA, h3DWnd, -16
|
||||
and eax, 10000000h
|
||||
mov visibleStyle, eax
|
||||
|
|
@ -398,7 +402,7 @@ ToggleFullscreen3D PROC uses ebx esi edi
|
|||
sub ebx, monitor3D[8]
|
||||
invoke SetWindowPos, h3DWnd, 0, monitor3D[4], monitor3D[8], eax, ebx, 24h
|
||||
mov fullscreen3D, 1
|
||||
ret
|
||||
jmp fullscreen_done
|
||||
restore_window:
|
||||
mov eax, visibleStyle
|
||||
or eax, WS_OVERLAPPEDWINDOW
|
||||
|
|
@ -410,6 +414,10 @@ restore_window:
|
|||
invoke SetWindowPos, h3DWnd, 0, savedRect3D, savedRect3D[4], eax, ebx, 24h
|
||||
mov fullscreen3D, 0
|
||||
fullscreen_done:
|
||||
cmp detailOpen,0
|
||||
je @F
|
||||
call OpenCoinDetail3D
|
||||
@@:
|
||||
ret
|
||||
ToggleFullscreen3D ENDP
|
||||
|
||||
|
|
|
|||
|
|
@ -69,60 +69,66 @@ savePath3D db "runtime\casino3d-progress.dat",0
|
|||
saveData3D dd 32443343h, 10000, 0, 0
|
||||
saveIo3D dd 0
|
||||
previewBackMap3D dd 0,3,5,2
|
||||
textPause3D db "CASINO / SETTINGS",0
|
||||
textResume3D db "ESC - RESUME",0
|
||||
textQuit3D db "Q - SAVE AND EXIT",0
|
||||
textDisplayFill3D db "1 DISPLAY: FULL SCREEN",0
|
||||
textDisplayFit3D db "1 DISPLAY: CLASSIC 4:3",0
|
||||
textLowSpec3D db "2 PERFORMANCE LEVEL",0
|
||||
textSoundLevel3D db "VOLUME",0
|
||||
textVolumeKeys3D db "+ / - CHANGE VOLUME",0
|
||||
textFullscreenKey3D db "F11 FULLSCREEN / WINDOW",0
|
||||
textLowSpecOff3D db "OFF",0
|
||||
textLowSpecEco3D db "ECO",0
|
||||
textLowSpecQuiet3D db "QUIET",0
|
||||
textMissing3D db "Cannot load assets/textures/casino3d-hd.bin. Keep the assets folder next to the game.",0
|
||||
textPause3D db 202,192,199,200,205,206,32,47,32,205,192,209,210,208,206,201,202,200,0
|
||||
textResume3D db 69,83,67,32,45,32,207,208,206,196,206,203,198,200,210,220,0
|
||||
textQuit3D db 81,32,45,32,209,206,213,208,192,205,200,210,220,32,200,32,194,219,201,210,200,0
|
||||
textDisplayFill3D db 49,32,221,202,208,192,205,58,32,194,197,209,220,32,204,206,205,200,210,206,208,0
|
||||
textDisplayFit3D db 49,32,221,202,208,192,205,58,32,202,203,192,209,209,200,202,192,32,52,58,51,0
|
||||
textLowSpec3D db 50,32,208,197,198,200,204,0
|
||||
textSoundLevel3D db 195,208,206,204,202,206,209,210,220,0
|
||||
textVolumeKeys3D db 43,32,47,32,45,32,195,208,206,204,202,206,209,210,220,0
|
||||
textFullscreenKey3D db 70,49,49,32,207,206,203,205,219,201,32,221,202,208,192,205,32,47,32,206,202,205,206,0
|
||||
textLowSpecOff3D db 207,206,203,205,219,201,0
|
||||
textLowSpecEco3D db 221,202,206,0
|
||||
textLowSpecQuiet3D db 210,200,213,200,201,0
|
||||
textMissing3D db 205,229,32,243,228,224,235,238,241,252,32,231,224,227,240,243,231,232,242,252,32,97,115,115,101,116,115,47,116,101,120,116
|
||||
db 117,114,101,115,47,99,97,115,105,110,111,51,100,45,104,100,46,98,105,110,46,32,207,224,239,234,224,32,97,115,115,101
|
||||
db 116,115,32,228,238,235,230,237,224,32,237,224,245,238,228,232,242,252,241,255,32,240,255,228,238,236,32,241,32,232,227,240
|
||||
db 238,233,46,0
|
||||
mutexName3D db "Local\AssemblerCasinoGraphical",0
|
||||
user32Name3D db "user32.dll",0
|
||||
dpiName3D db "SetProcessDPIAware",0
|
||||
textWalkKeys3D db "W/S: MOVE A/D: TURN E: USE",0
|
||||
textWindowKeys3D db "F11 FULL / ESC",0
|
||||
textBank3D db "BANK $",0
|
||||
textTip3D db "TIP $100",0
|
||||
textUnavailable3D db "THIS TABLE IS NOT PORTED YET",0
|
||||
textSlots3D db "777 / SLOT MACHINE",0
|
||||
textSlotsKeys3D db "SPACE: SPIN UP/DOWN: BET",0
|
||||
textBack3D db "ESC: BACK TO CASINO",0
|
||||
textBet3D db "BET $",0
|
||||
textDealer3D db "DEALER",0
|
||||
textPlayer3D db "YOUR HAND",0
|
||||
textBJKeys3D db "H: HIT S: STAND",0
|
||||
textDeal3D db "SPACE: DEAL UP/DOWN: BET",0
|
||||
textNext3D db "SPACE: NEXT HAND",0
|
||||
textRed3D db "1 RED",0
|
||||
textBlack3D db "2 BLACK",0
|
||||
textZero3D db "3 ZERO",0
|
||||
textEven3D db "4 EVEN",0
|
||||
textOdd3D db "5 ODD",0
|
||||
textSpin3D db "SPACE: SPIN ESC: LEAVE",0
|
||||
textResult3D db "NUMBER",0
|
||||
textShop3D db "CASINO BOUTIQUE",0
|
||||
textItem1_3D db "1 GOLD CARD BACK - $1000",0
|
||||
textItem2_3D db "2 EMERALD BACK - $1500",0
|
||||
textItem3_3D db "3 CRIMSON BACK - $1500",0
|
||||
textShopHint3D db "BUY ONCE / PRESS AGAIN TO EQUIP",0
|
||||
textBought3D db "CARD BACK EQUIPPED",0
|
||||
textWalkKeys3D db 87,47,83,58,32,213,206,196,32,32,65,47,68,58,32,207,206,194,206,208,206,210,32,32,69,58,32,196,197,201,209,210
|
||||
db 194,200,197,0
|
||||
textWindowKeys3D db 70,49,49,32,221,202,208,192,205,32,47,32,69,83,67,0
|
||||
textBank3D db 193,192,205,202,32,36,0
|
||||
textTip3D db 215,192,197,194,219,197,32,36,49,48,48,0
|
||||
textUnavailable3D db 207,206,202,192,32,205,197,32,208,197,192,203,200,199,206,194,192,205,206,0
|
||||
textSlots3D db 55,55,55,32,47,32,192,194,210,206,204,192,210,0
|
||||
textSlotsKeys3D db 207,208,206,193,197,203,58,32,200,195,208,192,32,32,194,194,197,208,213,47,194,205,200,199,58,32,209,210,192,194,202,192
|
||||
db 0
|
||||
textBack3D db 69,83,67,58,32,205,192,199,192,196,32,194,32,202,192,199,200,205,206,0
|
||||
textBet3D db 209,210,192,194,202,192,32,36,0
|
||||
textDealer3D db 196,200,203,197,208,0
|
||||
textPlayer3D db 194,192,216,200,32,202,192,208,210,219,0
|
||||
textBJKeys3D db 72,58,32,202,192,208,210,192,32,32,83,58,32,213,194,192,210,200,210,0
|
||||
textDeal3D db 207,208,206,193,197,203,58,32,209,196,192,210,220,32,32,194,194,197,208,213,47,194,205,200,199,58,32,209,210,192,194,202
|
||||
db 192,0
|
||||
textNext3D db 207,208,206,193,197,203,58,32,209,203,197,196,211,222,217,192,223,32,208,192,199,196,192,215,192,0
|
||||
textRed3D db 49,32,202,208,192,209,205,206,197,0
|
||||
textBlack3D db 50,32,215,168,208,205,206,197,0
|
||||
textZero3D db 51,32,205,206,203,220,0
|
||||
textEven3D db 52,32,215,168,210,0
|
||||
textOdd3D db 53,32,205,197,215,168,210,0
|
||||
textSpin3D db 207,208,206,193,197,203,58,32,200,195,208,192,32,32,69,83,67,58,32,194,219,213,206,196,0
|
||||
textResult3D db 215,200,209,203,206,0
|
||||
textShop3D db 204,192,195,192,199,200,205,32,202,192,199,200,205,206,0
|
||||
textItem1_3D db 49,32,199,206,203,206,210,192,223,32,208,211,193,192,216,202,192,32,45,32,36,49,48,48,48,0
|
||||
textItem2_3D db 50,32,200,199,211,204,208,211,196,205,192,223,32,208,211,193,192,216,202,192,32,45,32,36,49,53,48,48,0
|
||||
textItem3_3D db 51,32,193,192,195,208,206,194,192,223,32,208,211,193,192,216,202,192,32,45,32,36,49,53,48,48,0
|
||||
textShopHint3D db 202,211,207,200,210,220,32,47,32,194,219,193,208,192,210,220,32,208,211,193,192,216,202,211,0
|
||||
textBought3D db 208,211,193,192,216,202,192,32,194,219,193,208,192,205,192,0
|
||||
ownedBacks3D dd 1
|
||||
selectedBack3D dd 0
|
||||
cardBackColors3D dd 00434A4Dh,00244780h,009A3248h,00B79835h,0031252Bh,002C7958h
|
||||
dd 00654782h,00202528h,002D6184h,0085663Dh,009D8532h,00276E76h,00613749h
|
||||
textATM3D db "CASHIER",0
|
||||
textATMNote3D db "BALANCE IS SAVED ON EXIT",0
|
||||
textATMNote2_3D db "SEPARATE 2.5D PREVIEW PROFILE",0
|
||||
textNoCash3D db "NOT ENOUGH CHIPS",0
|
||||
textWin3D db "WIN",0
|
||||
textLose3D db "LOSS",0
|
||||
textTie3D db "PUSH",0
|
||||
textBJ3D db "21 / BLACKJACK",0
|
||||
textTips3D db "THANK YOU FOR THE TIP",0
|
||||
textATM3D db 202,192,209,209,192,0
|
||||
textATMNote3D db 193,192,203,192,205,209,32,209,206,213,208,192,205,223,197,210,209,223,32,207,208,200,32,194,219,213,206,196,197,0
|
||||
textATMNote2_3D db 203,206,202,192,203,220,205,219,201,32,207,208,206,212,200,203,220,32,200,195,208,206,202,192,0
|
||||
textNoCash3D db 205,197,196,206,209,210,192,210,206,215,205,206,32,212,200,216,197,202,0
|
||||
textWin3D db 194,219,200,195,208,219,216,0
|
||||
textLose3D db 207,208,206,200,195,208,219,216,0
|
||||
textTie3D db 205,200,215,220,223,0
|
||||
textBJ3D db 50,49,32,47,32,193,203,221,202,196,198,197,202,0
|
||||
textTips3D db 209,207,192,209,200,193,206,32,199,192,32,215,192,197,194,219,197,0
|
||||
.code
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ rr_table_hud:
|
|||
invoke DrawBuckshotText3D,16,414,OFFSET rrCartridgeText3D,00EBD5A0h
|
||||
invoke DrawBuckshotNumber3D,160,414,rr3d_bullets,00FFFFFFh
|
||||
invoke DrawBuckshotText3D,456,414,OFFSET bs3d_textBet,00EBD5A0h
|
||||
invoke DrawBuckshotNumber3D,512,414,rr3d_bet,00FFFFFFh
|
||||
invoke DrawBuckshotNumber3D,528,414,rr3d_bet,00FFFFFFh
|
||||
mov ebx,OFFSET rrPlayerText3D
|
||||
cmp rr3d_turn,0
|
||||
je @F
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ startupPixels3D dd 0
|
|||
startupHeap3D dd 0
|
||||
startupHeader3D dd 4 dup(0)
|
||||
startupPath3D db "assets\animations\intro\eblan-games.bin",0
|
||||
startupEnter3D db "ENTER",0
|
||||
startupEnter3D db 69,78,84,69,82,0
|
||||
startupName3D db "EBLAN",0
|
||||
startupGames3D db "GAMES",0
|
||||
.code
|
||||
|
|
|
|||
35
tools/generators/coin_scene_cp1251.patch
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
diff --git a/casino3d.inc b/casino3d.inc
|
||||
--- a/casino3d.inc
|
||||
+++ b/casino3d.inc
|
||||
@@ -154,1 +154,2 @@
|
||||
include src_graphics\native_slots_data.inc
|
||||
+include src_graphics\native_coin_data.inc
|
||||
@@ -2650,7 +2651,4 @@
|
||||
InitCoinGame PROC
|
||||
- mov coin3d_state, 0
|
||||
- mov coin3d_timer, 0
|
||||
- mov coin3d_streak, 0
|
||||
- mov coin3d_win, 0
|
||||
+ call InitNativeCoin3D
|
||||
ret
|
||||
InitCoinGame ENDP
|
||||
@@ -2658,1 +2656,5 @@
|
||||
HandleCoinInput PROC
|
||||
+ call HandleNativeCoin3D
|
||||
+ ret
|
||||
+; Retained legacy frame-count prototype, excluded from the executable.
|
||||
+IF 0
|
||||
@@ -2779,1 +2781,2 @@
|
||||
+ENDIF
|
||||
HandleCoinInput ENDP
|
||||
@@ -2786,1 +2789,4 @@
|
||||
+ call RenderNativeCoin3D
|
||||
+ ret
|
||||
+IF 0
|
||||
; Background & Cabinet border
|
||||
@@ -2898,1 +2904,2 @@
|
||||
+ENDIF
|
||||
RenderCoinGame ENDP
|
||||
@@ -5107,1 +5114,2 @@
|
||||
include src_graphics\native_slots.inc
|
||||
+include src_graphics\native_coin.inc
|
||||
46
tools/generators/compile_ui_ru.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
"""Offline, byte-preserving replacement of explicitly listed MASM UI labels."""
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
MAP = ROOT / "assets/data/ui-ru.json"
|
||||
|
||||
|
||||
def compile_ui(check=False):
|
||||
translations = json.loads(MAP.read_text(encoding="utf-8"))
|
||||
declarations = re.compile(rb"^(\w+)([ \t]+db[ \t]+)([^\r\n]+(?:\r?\n[ \t]+db[ \t]+[^\r\n]+)*)", re.M)
|
||||
seen = set()
|
||||
changes = []
|
||||
paths = [ROOT / "casino3d.inc", *sorted((ROOT / "src_graphics").glob("*_data.inc"))]
|
||||
for path in paths:
|
||||
original = path.read_bytes()
|
||||
|
||||
def replace(match):
|
||||
symbol = match[1].decode("ascii")
|
||||
if symbol not in translations:
|
||||
return match[0]
|
||||
assert symbol not in seen, f"Duplicate declaration: {symbol}"
|
||||
seen.add(symbol)
|
||||
values = [*translations[symbol].encode("cp1251"), 0]
|
||||
chunks = [values[i:i + 32] for i in range(0, len(values), 32)]
|
||||
newline = b"\r\n" if b"\r\n" in original else b"\n"
|
||||
encoded = (newline + b" db ").join(",".join(map(str, chunk)).encode("ascii") for chunk in chunks)
|
||||
return match[1] + match[2] + encoded
|
||||
|
||||
updated = declarations.sub(replace, original)
|
||||
if updated != original:
|
||||
changes.append(path.relative_to(ROOT).as_posix())
|
||||
if not check:
|
||||
path.write_bytes(updated)
|
||||
assert seen == translations.keys(), f"Missing labels: {translations.keys() - seen}"
|
||||
if check:
|
||||
assert not changes, f"Translation not compiled: {changes}"
|
||||
print(f"PASS: {len(seen)} Russian labels, CP1251 bytes, {len(changes)} files updated")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--check", action="store_true")
|
||||
compile_ui(parser.parse_args().check)
|
||||
110
tools/generators/pack_coin_assets.py
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
"""Normalize generated art offline; all toss animation and play are MASM."""
|
||||
import hashlib
|
||||
import json
|
||||
from collections import deque
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image
|
||||
import pack_arrival_assets as packs
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
SOURCE = ROOT / "assets/sprites/coin"
|
||||
|
||||
|
||||
def isolated_hand(frame):
|
||||
"""Remove disconnected previous-row cuff spill without changing the hand anchor."""
|
||||
width, height = frame.size
|
||||
alpha = frame.getchannel("A").tobytes()
|
||||
visited = bytearray(width * height)
|
||||
largest = []
|
||||
for seed, value in enumerate(alpha):
|
||||
if not value or visited[seed]:
|
||||
continue
|
||||
visited[seed] = 1
|
||||
queue = deque([seed])
|
||||
component = []
|
||||
while queue:
|
||||
at = queue.popleft()
|
||||
component.append(at)
|
||||
x, y = at % width, at // width
|
||||
for dx, dy in ((-1, 0), (1, 0), (0, -1), (0, 1)):
|
||||
nx, ny = x + dx, y + dy
|
||||
if 0 <= nx < width and 0 <= ny < height:
|
||||
neighbor = ny * width + nx
|
||||
if alpha[neighbor] and not visited[neighbor]:
|
||||
visited[neighbor] = 1
|
||||
queue.append(neighbor)
|
||||
if len(component) > len(largest):
|
||||
largest = component
|
||||
mask = bytearray(width * height)
|
||||
for at in largest:
|
||||
mask[at] = 255
|
||||
frame.putalpha(Image.frombytes("L", frame.size, bytes(mask)))
|
||||
return frame
|
||||
|
||||
|
||||
def main():
|
||||
packs.OUTPUT = ROOT / "assets/animations/coin"
|
||||
preview = ROOT / "build/coin"
|
||||
preview.mkdir(parents=True, exist_ok=True)
|
||||
background = Image.open(SOURCE / "table-v1.png").convert("RGBA")
|
||||
background = background.resize((640, 480), Image.Resampling.NEAREST)
|
||||
# Reserve the renderer's 40-pixel header without cropping the dealer's head.
|
||||
framed = Image.new("RGBA", (640, 480), (20, 25, 29, 255))
|
||||
framed.paste(background.crop((0, 0, 640, 440)), (0, 40))
|
||||
background = framed
|
||||
background.putalpha(255)
|
||||
packs.write_pack("table-v1.bin", [background])
|
||||
background.save(preview / "table.png")
|
||||
source = Image.open(SOURCE / "faces-v1.png").convert("RGBA")
|
||||
assert source.getchannel("A").getextrema()[0] == 0
|
||||
faces = []
|
||||
for column in range(2):
|
||||
frame = source.crop((column * source.width // 2, 0,
|
||||
(column + 1) * source.width // 2, source.height))
|
||||
frame = frame.crop(frame.getchannel("A").getbbox())
|
||||
frame = frame.resize((128, 128), Image.Resampling.NEAREST)
|
||||
frame = packs.solid_alpha(frame)
|
||||
faces.append(frame)
|
||||
frame.save(preview / ("face-" + str(column) + ".png"))
|
||||
packs.write_pack("faces-v1.bin", faces)
|
||||
source = Image.open(SOURCE / "hands-v2.png").convert("RGBA")
|
||||
assert source.getchannel("A").getextrema()[0] == 0
|
||||
hands = []
|
||||
held_centers = [(79, 70), (76, 77), (74, 82), (77, 96), (70, 98)]
|
||||
for row in range(4):
|
||||
for column in range(4):
|
||||
frame = source.crop((column * source.width // 4, row * source.height // 4,
|
||||
(column + 1) * source.width // 4, (row + 1) * source.height // 4))
|
||||
# Keep common cell scale rather than stretching each pose's alpha bounds.
|
||||
frame = frame.resize((224, 224), Image.Resampling.NEAREST)
|
||||
frame = packs.solid_alpha(frame)
|
||||
# Remove the generator's saturated red alpha-matte fringe, not skin highlights.
|
||||
frame.putdata([(r, g, b, 0 if r > 120 and g < 50 and b < 50 else a)
|
||||
for r, g, b, a in frame.get_flattened_data()])
|
||||
index = len(hands)
|
||||
if index >= len(held_centers):
|
||||
frame = isolated_hand(frame)
|
||||
if index < len(held_centers):
|
||||
# The held coin and fingers share one sprite and the release-point anchor.
|
||||
cx, cy = held_centers[index]
|
||||
aligned = Image.new("RGBA", (224, 224))
|
||||
aligned.paste(frame, (88 - cx, 24 - cy))
|
||||
frame = aligned
|
||||
frame.putdata([(r, g, b, a) if a else (0, 0, 0, 0)
|
||||
for r, g, b, a in frame.get_flattened_data()])
|
||||
assert frame.getchannel("A").getbbox()
|
||||
hands.append(frame)
|
||||
frame.save(preview / ("hand-" + str(len(hands) - 1) + ".png"))
|
||||
assert len({hashlib.sha256(frame.tobytes()).hexdigest() for frame in hands}) == 16
|
||||
packs.write_pack("hands-v2.bin", hands)
|
||||
(packs.OUTPUT / "manifest-v1.json").write_text(json.dumps({
|
||||
"table": [640, 480, 1], "faces": [128, 128, 2], "hands": [224, 224, 16],
|
||||
"hand_anchor": "held coin (88,24); empty hand shared grid cell",
|
||||
"held_frames": 5, "alpha": "opaque table, binary cutouts"
|
||||
}, indent=2) + "\n", encoding="ascii")
|
||||
print("Packed coin table, two embossed sides and sixteen distinct hand poses")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
78
tools/generators/pack_european_wheel.py
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
"""Offline scene packing and exact 37-pocket rotor for the MASM roulette renderer."""
|
||||
import json
|
||||
import math
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import pack_arrival_assets as packs
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
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}
|
||||
|
||||
|
||||
def rotor(numbered=True):
|
||||
im = Image.new("RGBA", (512, 512))
|
||||
pixels = im.load()
|
||||
for y in range(512):
|
||||
for x in range(512):
|
||||
dx, dy = x - 256, y - 256
|
||||
radius = math.hypot(dx, dy)
|
||||
if radius > 240:
|
||||
continue
|
||||
noise = ((x * 193 + y * 37 + (x ^ y) * 13) % 17) - 8
|
||||
base = (82, 41, 25)
|
||||
if radius >= 236 or 181 <= radius < 185 or 225 <= radius < 229:
|
||||
base = (199, 158, 74)
|
||||
elif radius >= 185:
|
||||
angle = math.atan2(dy, dx) % math.tau
|
||||
slot = int((angle / math.tau * 37 + .5) % 37)
|
||||
value = ORDER[slot]
|
||||
base = (20, 95, 56) if value == 0 else (
|
||||
(132, 32, 38) if value in RED else (25, 30, 28))
|
||||
boundary = abs((angle / math.tau * 37 + .5) % 1 - .5)
|
||||
if boundary > .465:
|
||||
base = (211, 176, 94)
|
||||
elif radius < 28:
|
||||
base = (191, 145, 58) if radius > 22 else (234, 207, 137)
|
||||
pixels[x, y] = tuple(max(0, min(255, c + noise)) for c in base) + (255,)
|
||||
if not numbered:
|
||||
return im
|
||||
font = ImageFont.truetype("C:/Windows/Fonts/arialbd.ttf", 20)
|
||||
for index, value in enumerate(ORDER):
|
||||
angle = index * math.tau / 37
|
||||
label = Image.new("RGBA", (44, 26))
|
||||
draw = ImageDraw.Draw(label)
|
||||
draw.text((22, 13), str(value), font=font, anchor="mm", fill=(247, 238, 211))
|
||||
label = label.rotate(-index * 360 / 37 - 90, expand=True, resample=Image.Resampling.NEAREST)
|
||||
cx, cy = round(256 + 208 * math.cos(angle)), round(256 + 208 * math.sin(angle))
|
||||
im.alpha_composite(label, (cx - label.width // 2, cy - label.height // 2))
|
||||
return im
|
||||
|
||||
|
||||
def main(rotor_only=False):
|
||||
packs.OUTPUT = ROOT / "assets/animations/wheel"
|
||||
preview = ROOT / "build/wheel"
|
||||
preview.mkdir(parents=True, exist_ok=True)
|
||||
manifest = {"order": ORDER, "zero_pockets": 1}
|
||||
for name in (() if rotor_only else ("table", "closeup")):
|
||||
image = Image.open(ROOT / "assets/sprites/wheel" / (name + "-v1.png")).convert("RGBA")
|
||||
image = image.resize((640, 480), Image.Resampling.NEAREST)
|
||||
image.putalpha(255)
|
||||
packs.write_pack(name + "-v1.bin", [image])
|
||||
image.save(preview / (name + ".png"))
|
||||
# Numerals now belong to the native screen-space renderer, not a warped image.
|
||||
disk = rotor(numbered=False).resize((480, 480), Image.Resampling.NEAREST)
|
||||
packs.write_pack("rotor-v2.bin", [disk])
|
||||
disk.save(preview / "rotor-v2.png")
|
||||
(packs.OUTPUT / "manifest-v1.json").write_text(json.dumps(manifest, indent=2) + "\n", encoding="ascii")
|
||||
print("Packed the exact 37-pocket rotor; labels are rendered by MASM")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--rotor-only", action="store_true")
|
||||
main(parser.parse_args().rotor_only)
|
||||
58
tools/generators/pack_hall_furniture.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
"""Offline clean, tightly bounded furniture frames for the native MASM hall."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from pack_arrival_assets import solid_alpha, write_pack
|
||||
import pack_arrival_assets as packs
|
||||
from pack_world_v4 import clean_cell
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def frame(source, bounds, size):
|
||||
item = clean_cell(solid_alpha(source.crop(bounds).convert("RGBA")))
|
||||
# Independent frames have no nominal atlas-grid margins or neighboring limbs.
|
||||
item = item.resize(size, Image.Resampling.NEAREST)
|
||||
return solid_alpha(item)
|
||||
|
||||
|
||||
def main():
|
||||
packs.OUTPUT = ROOT / "assets/animations/hall"
|
||||
atlas = Image.open(ROOT / "assets/sprites/casino-atlas-v1.png")
|
||||
assert atlas.size == (1254, 1254)
|
||||
def atlas_bounds(box):
|
||||
return tuple(round(value * 1254 / 1280) for value in box)
|
||||
items = [
|
||||
("card-table", atlas, atlas_bounds((933, 415, 1266, 631)), (320, 208)),
|
||||
("roulette-table", atlas, atlas_bounds((0, 646, 315, 938)), (288, 268)),
|
||||
("backroom-table", atlas, atlas_bounds((320, 700, 625, 937)), (304, 236)),
|
||||
]
|
||||
source = Image.open(ROOT / "assets/sprites/hall/furniture-v5.png")
|
||||
assert source.size == (1536, 1024)
|
||||
items += [
|
||||
("skill-cabinet", source, (210, 0, 635, 585), (224, 368)),
|
||||
("lounge-chair", source, (907, 42, 1410, 579), (240, 256)),
|
||||
("lamp-table", source, (241, 584, 627, 1024), (192, 224)),
|
||||
("velvet-rope", source, (860, 584, 1439, 1024), (288, 192)),
|
||||
]
|
||||
manifest = {}
|
||||
output = ROOT / "build/hall"
|
||||
output.mkdir(parents=True, exist_ok=True)
|
||||
for name, image, bounds, size in items:
|
||||
result = frame(image, bounds, size)
|
||||
write_pack(name + "-v5.bin", [result])
|
||||
result.save(output / (name + "-v5.png"))
|
||||
manifest[name] = {"size": size, "bounds": bounds, "frames": 1}
|
||||
slots = [frame(atlas, atlas_bounds(box), (224, 256)) for box in
|
||||
[(38, 348, 294, 643), (352, 348, 618, 643), (674, 348, 931, 643)]]
|
||||
write_pack("slot-cabinets-v5.bin", slots)
|
||||
manifest["slot-cabinets"] = {"size": (224, 256), "frames": 3}
|
||||
(packs.OUTPUT / "manifest-furniture-v5.json").write_text(
|
||||
json.dumps(manifest, indent=2) + "\n", encoding="ascii")
|
||||
print("Packed seven separate furniture assets without atlas bleed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
52
tools/generators/pack_slot_assets.py
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
"""Normalize generated slot art and export ANM1 packs for the MASM runtime."""
|
||||
import json
|
||||
import struct
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
SOURCE = ROOT / "assets/sprites/slots"
|
||||
OUTPUT = ROOT / "assets/animations/slots"
|
||||
|
||||
|
||||
def pack(name, frames):
|
||||
width, height = frames[0].size
|
||||
assert all(frame.size == (width, height) for frame in frames)
|
||||
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)
|
||||
pack("cabinet-v1.bin", [cabinet])
|
||||
sheet = Image.open(SOURCE / "symbols-v1.png").convert("RGBA")
|
||||
assert 1.8 < sheet.width / sheet.height < 2.2
|
||||
symbols = []
|
||||
for index in range(8):
|
||||
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((52, 52), Image.Resampling.NEAREST)
|
||||
frame = Image.new("RGBA", (64, 64))
|
||||
frame.paste(cell, ((64 - cell.width) // 2, (64 - cell.height) // 2))
|
||||
# Opaque pixel clusters allow the native clipped reel sampler to stay cheap.
|
||||
frame.putalpha(frame.getchannel("A").point(lambda value: 255 if value >= 128 else 0))
|
||||
symbols.append(frame)
|
||||
pack("symbols-v1.bin", symbols)
|
||||
manifest = {"symbols": ["seven", "cherries", "lemon", "bell", "BAR",
|
||||
"grapes", "diamond", "crown"],
|
||||
"cabinet": [640, 480], "symbol": [64, 64],
|
||||
"pipeline": "offline normalization only; gameplay and reel animation are MASM"}
|
||||
(OUTPUT / "manifest.json").write_text(json.dumps(manifest, indent=2) + "\n", encoding="ascii")
|
||||
print("Packed native 777 cabinet and 8 alpha-tested 64x64 reel symbols")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
6
tools/generators/ui_layout_cp1251.patch
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
diff --git a/casino3d.inc b/casino3d.inc
|
||||
--- a/casino3d.inc
|
||||
+++ b/casino3d.inc
|
||||
@@ -5373 +5373 @@
|
||||
- invoke DrawString8x8, 108, 130, OFFSET hudNumBuffer, 00FFFFFFh
|
||||
+ invoke DrawString8x8, 124, 130, OFFSET hudNumBuffer, 00FFFFFFh
|
||||
|
|
@ -13,6 +13,9 @@ actionReportText db "PASS: fullscreen/startup/audio/dice/2000 roulette rounds; 9
|
|||
db "World: complete camera/car route; staff/front bar access; cabaret collision; six pocket throats; 100 varied-force breaks; 3 distinct drinks",13,10
|
||||
db "Cards: exit/cancel from every active phase, frozen hand, mouse/keyboard, no refunds/double payouts; street lamp/window lightmap",13,10
|
||||
db "Durak: 500 native complete games, 5184 beat pairs, transfers/takes/refill/trump, 36-card conservation, paging, exit in every phase",13,10
|
||||
db "777: 8000 stop combinations, 500 complete spins at four rates, monotonic reels, payouts, safe queued exit, native framebuffer snapshots",13,10
|
||||
db "Coin: 500 paid flips at four rates, safe exit in all phases, 1701 continuous poses, payouts, controls, missing art, 10 native frames",13,10
|
||||
db "Coin detail: owned window, monitor bounds, restoration, F11, no quit/focus stealing; five private-buffer captures",13,10
|
||||
actionReportSize equ ($-actionReportText)
|
||||
actionDiceTimes dd 0,200,500,800,1200,1600
|
||||
actionDice0 db "build\actions\dice-0.bmp",0
|
||||
|
|
@ -89,6 +92,9 @@ include tools\tests\unavailable_test.inc
|
|||
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\coin_detail_test.inc
|
||||
include tools\tests\coin_test.inc
|
||||
|
||||
RunCasinoActionsTest3D PROC uses ebx esi edi
|
||||
local savedSeed:DWORD,iterations:DWORD,chamberMask:DWORD,value1:DWORD,value2:DWORD,count:DWORD
|
||||
|
|
@ -132,6 +138,11 @@ RunCasinoActionsTest3D PROC uses ebx esi edi
|
|||
call ToggleFullscreen3D
|
||||
cmp fullscreen3D, 1
|
||||
jne action_fail_14
|
||||
call RunCoinDetailWindowTest3D
|
||||
test eax,eax
|
||||
jz @F
|
||||
ret
|
||||
@@:
|
||||
invoke ReleaseDC, h3DWnd, h3DDC
|
||||
mov h3DDC, 0
|
||||
invoke DestroyWindow, h3DWnd
|
||||
|
|
@ -496,6 +507,16 @@ action_round_done:
|
|||
test eax, eax
|
||||
jz @F
|
||||
ret
|
||||
@@:
|
||||
call RunSlotsTest3D
|
||||
test eax,eax
|
||||
jz @F
|
||||
ret
|
||||
@@:
|
||||
call RunCoinTest3D
|
||||
test eax,eax
|
||||
jz @F
|
||||
ret
|
||||
@@:
|
||||
call RunHallTest3D
|
||||
test eax, eax
|
||||
|
|
|
|||
103
tools/tests/check_coin_detail.py
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
"""Validate native auxiliary-window frames and Russian CP1251 glyphs."""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
from check_card_exit_build import Coff
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
NAMES = ("idle", "air", "heads", "tails", "loss")
|
||||
|
||||
|
||||
def font():
|
||||
values = []
|
||||
for line in (ROOT / "font8x8.inc").read_text(encoding="cp1251").splitlines():
|
||||
if line.startswith("db "):
|
||||
values.extend(int(v.strip()[:-1], 16) for v in line[3:].split(";")[0].split(","))
|
||||
assert len(values) == 256 * 8
|
||||
glyphs = [values[i * 8:(i + 1) * 8] for i in range(256)]
|
||||
labels = json.loads((ROOT / "assets/data/ui-ru.json").read_text(encoding="utf-8"))
|
||||
for text in labels.values():
|
||||
for code in text.encode("cp1251"):
|
||||
if code >= 128:
|
||||
assert any(glyphs[code]), f"Empty Cyrillic glyph {code:02X}"
|
||||
assert glyphs[code] != glyphs[ord("?")], f"Question mark instead of {code:02X}"
|
||||
assert glyphs[0xA8] != glyphs[ord("E")], "Russian YO must have its own glyph"
|
||||
widths = {
|
||||
"coinFlipText3D": 6, "coinAgainText3D": 7, "coinExitText3D": 5,
|
||||
"wheelRed3D": 5, "wheelBlack3D": 5, "wheelEven3D": 5, "wheelOdd3D": 5,
|
||||
"wheelSpin3D": 7, "wheelClear3D": 5,
|
||||
"pkCheckText3D": 8, "pkCallText3D": 8, "pkRaiseText3D": 8,
|
||||
"pkFoldText3D": 8, "pkAllInText3D": 8, "cbHitText3D": 8,
|
||||
"cbStandText3D": 8, "cbDoubleText3D": 8, "merchantBuy3D": 12,
|
||||
"bs3d_textCuffKey": 8, "entryChoose3D": 16, "entryNew3D": 16,
|
||||
"poolOpenText3D": 16, "poolSolidsText3D": 16, "poolStripesText3D": 16,
|
||||
}
|
||||
for symbol, maximum in widths.items():
|
||||
assert len(labels[symbol]) <= maximum, f"Russian button overflow: {symbol}"
|
||||
print(f"PASS: {len(labels)} translated labels have CP1251 glyphs including YO; narrow buttons fit")
|
||||
return glyphs
|
||||
|
||||
|
||||
def text_matches(frame, text, x, y, scale, ink, glyphs):
|
||||
for code in text.encode("cp1251"):
|
||||
for row, mask in enumerate(glyphs[code]):
|
||||
for column in range(8):
|
||||
if mask & (128 >> column):
|
||||
for dy in range(scale):
|
||||
for dx in range(scale):
|
||||
assert frame.getpixel((x + column * scale + dx, y + row * scale + dy)) == ink, (text, x, y)
|
||||
x += scale * 8
|
||||
|
||||
|
||||
def captures(glyphs):
|
||||
frames = {}
|
||||
sheet = Image.new("RGB", (320 * 5, 424), (20, 25, 29))
|
||||
draw = ImageDraw.Draw(sheet)
|
||||
for i, name in enumerate(NAMES):
|
||||
path = ROOT / "build/actions" / f"coin-detail-{name}.bmp"
|
||||
frame = Image.open(path).convert("RGB")
|
||||
assert frame.size == (320, 400), name
|
||||
assert len(frame.getcolors(128000)) > 100, name
|
||||
frame.save(path.with_suffix(".png"))
|
||||
frames[name] = frame
|
||||
sheet.paste(frame, (i * 320, 24))
|
||||
draw.text((i * 320 + 8, 6), name, fill="white")
|
||||
assert frame.getpixel((319, 399)) == (20, 25, 29)
|
||||
assert len({hashlib.sha256(f.tobytes()).digest() for f in frames.values()}) == 5
|
||||
for name, side, x in (("heads", "ОРЁЛ", 96), ("tails", "РЕШКА", 80), ("loss", "РЕШКА", 80)):
|
||||
text_matches(frames[name], side, x, 284, 4, (244, 231, 200), glyphs)
|
||||
text_matches(frames["heads"], "ВЫИГРЫШ", 104, 336, 2, (135, 212, 165), glyphs)
|
||||
text_matches(frames["loss"], "ПРОИГРЫШ", 96, 336, 2, (233, 147, 131), glyphs)
|
||||
text_matches(frames["air"], "МОНЕТА В ПОЛЁТЕ", 40, 310, 2, (229, 210, 158), glyphs)
|
||||
assert frames["heads"].crop((60, 66, 260, 266)).tobytes() != frames["tails"].crop((60, 66, 260, 266)).tobytes()
|
||||
assert frames["tails"].crop((60, 66, 260, 266)).tobytes() == frames["loss"].crop((60, 66, 260, 266)).tobytes()
|
||||
sheet.save(ROOT / "build/actions/coin-detail-contact.png")
|
||||
print("PASS: five distinct native detail frames; exact Russian result/win/loss glyphs and matching faces")
|
||||
|
||||
|
||||
def parity():
|
||||
tested = Coff(ROOT / "build/actions/actions-test.obj")
|
||||
shipped = Coff(ROOT / "build/graphics/poker.obj")
|
||||
for name, count in (("OpenCoinDetail3D", 0), ("CloseCoinDetail3D", 0), ("LayoutCoinDetail3D", 0),
|
||||
("UpdateCoinDetail3D", 0), ("RenderCoinDetail3D", 0), ("CoinDetailEvents3D", 16),
|
||||
("CoinDetailBox3D", 20), ("CoinDetailText3D", 20), ("CoinDetailFace3D", 8),
|
||||
("CoinDetailNumber3D", 16), ("ToggleFullscreen3D", 0)):
|
||||
symbol = f"_{name}@{count}"
|
||||
assert tested.signature(symbol) == shipped.signature(symbol), name
|
||||
print("PASS: shipping auxiliary-window lifecycle, renderer and fullscreen match native-tested MASM")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--parity", action="store_true")
|
||||
parser.add_argument("--font-only", action="store_true")
|
||||
args = parser.parse_args()
|
||||
glyphs = font()
|
||||
if not args.font_only:
|
||||
captures(glyphs)
|
||||
if args.parity:
|
||||
parity()
|
||||
84
tools/tests/check_coin_scene.py
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
"""Check coin pack layout, native framebuffer captures and shipping MASM parity."""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import struct
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
from check_card_exit_build import Coff
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
NAMES = ("idle", "hold", "release", "air", "apex", "descent", "land", "bounce", "result", "tails")
|
||||
|
||||
|
||||
def assets():
|
||||
manifest = json.loads((ROOT / "assets/animations/coin/manifest-v1.json").read_text())
|
||||
for name, shape in (("table", (640, 480, 1)), ("faces", (128, 128, 2)), ("hands", (224, 224, 16))):
|
||||
version = 2 if name == "hands" else 1
|
||||
data = (ROOT / "assets/animations/coin" / f"{name}-v{version}.bin").read_bytes()
|
||||
width, height, count = shape
|
||||
size = width * height * 4
|
||||
assert manifest[name] == list(shape), name
|
||||
assert struct.unpack_from("<4s4I", data) == (b"ANM1", *shape, size * count), name
|
||||
assert len(data) == 20 + size * count, name
|
||||
assert set(data[23::4]) == ({255} if name == "table" else {0, 255}), name
|
||||
hashes = []
|
||||
for i in range(count):
|
||||
pixels = data[20 + i * size:20 + (i + 1) * size]
|
||||
hashes.append(hashlib.sha256(pixels).hexdigest())
|
||||
opaque = sum(alpha == 255 for alpha in pixels[3::4])
|
||||
assert opaque > width * height // 10, (name, i)
|
||||
if name == "hands" and i < 5:
|
||||
frame = Image.frombytes("RGBA", (width, height), pixels, "raw", "BGRA")
|
||||
anchor = frame.crop((64, 12, 112, 32))
|
||||
gold = sum(a == 255 and r > 130 and g * 100 > r * 70 and b * 100 < r * 40
|
||||
for r, g, b, a in anchor.get_flattened_data())
|
||||
assert gold > 10, ("Held coin lost its contact anchor", i, gold)
|
||||
assert len(set(hashes)) == count, name
|
||||
print("PASS: opaque table, two coin faces, sixteen hand frames; held coin/fingers share one sprite")
|
||||
|
||||
|
||||
def captures():
|
||||
sheet = Image.new("RGB", (1280, 5 * 504), (20, 25, 29))
|
||||
labels = ImageDraw.Draw(sheet)
|
||||
hashes = []
|
||||
for i, name in enumerate(NAMES):
|
||||
path = ROOT / "build/actions" / f"coin-{name}.bmp"
|
||||
frame = Image.open(path).convert("RGB")
|
||||
assert frame.size == (640, 480), name
|
||||
assert len(frame.getcolors(640 * 480)) > 1000, name
|
||||
hashes.append(hashlib.sha256(frame.tobytes()).hexdigest())
|
||||
frame.save(path.with_suffix(".png"))
|
||||
x, y = i % 2 * 640, i // 2 * 504
|
||||
sheet.paste(frame, (x, y + 24))
|
||||
labels.text((x + 8, y + 6), name, fill="white")
|
||||
assert len(set(hashes)) == len(NAMES), "Toss captures must be distinct"
|
||||
sheet.save(ROOT / "build/actions/coin-contact-v1.png")
|
||||
print("PASS: 10 distinct, nonblank native frames including both result faces")
|
||||
|
||||
|
||||
def parity():
|
||||
tested = Coff(ROOT / "build/actions/actions-test.obj")
|
||||
shipped = Coff(ROOT / "build/graphics/poker.obj")
|
||||
for name, arguments in (("InitCoinGame", 0), ("HandleCoinInput", 0), ("RenderCoinGame", 0),
|
||||
("InitNativeCoin3D", 0), ("LoadNativeCoinArt3D", 0),
|
||||
("FreeNativeCoinArt3D", 0), ("HandleNativeCoin3D", 0),
|
||||
("RenderNativeCoin3D", 0), ("CoinEscape3D", 0),
|
||||
("CoinSettle3D", 0), ("CoinPose3D", 4), ("DrawCoinShadow3D", 20),
|
||||
("CardTableEscape3D", 0)):
|
||||
symbol = f"_{name}@{arguments}"
|
||||
assert tested.signature(symbol) == shipped.signature(symbol), name
|
||||
print("PASS: published coin renderer, controls, payout and exit match native-tested MASM")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--assets-only", action="store_true")
|
||||
parser.add_argument("--parity", action="store_true")
|
||||
options = parser.parse_args()
|
||||
assets()
|
||||
if not options.assets_only:
|
||||
captures()
|
||||
if options.parity:
|
||||
parity()
|
||||
85
tools/tests/check_european_wheel.py
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
"""Validate roulette assets, native captures and tested/shipping procedure parity."""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import struct
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
from check_card_exit_build import Coff
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
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}
|
||||
|
||||
|
||||
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")
|
||||
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()
|
||||
mask = int(low, 16) | int(high, 16) << 32
|
||||
assert {n for n in range(37) if mask & (1 << n)} == RED
|
||||
for name, size in (("table", (640, 480)), ("closeup", (640, 480)), ("rotor", (480, 480))):
|
||||
version = 2 if name == "rotor" else 1
|
||||
data = (ROOT / "assets/animations/wheel" / f"{name}-v{version}.bin").read_bytes()
|
||||
assert struct.unpack_from("<4s4I", data) == (
|
||||
b"ANM1", *size, 1, size[0] * size[1] * 4), name
|
||||
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
|
||||
print("PASS: three valid packs; exact European order, one zero and correct red/black colors")
|
||||
|
||||
|
||||
def captures():
|
||||
names = ("draft", "launch", "fast", "slow", "land", "result")
|
||||
contact = Image.new("RGB", (1280, 3 * 504), (20, 25, 29))
|
||||
labels = ImageDraw.Draw(contact)
|
||||
hashes = []
|
||||
for i, name in enumerate(names):
|
||||
path = ROOT / "build/actions" / ("wheel-" + name + "-v1.bmp")
|
||||
frame = Image.open(path).convert("RGB")
|
||||
assert frame.size == (640, 480), name
|
||||
assert len(frame.getcolors(640 * 480)) > 1000, name
|
||||
hashes.append(hashlib.sha256(frame.tobytes()).hexdigest())
|
||||
frame.save(path.with_suffix(".png"))
|
||||
x, y = i % 2 * 640, i // 2 * 504
|
||||
contact.paste(frame, (x, y + 24))
|
||||
labels.text((x + 8, y + 6), name, fill="white")
|
||||
assert len(set(hashes)) == len(names), "Animation captures must be distinct"
|
||||
contact.save(ROOT / "build/actions/wheel-contact-v1.png")
|
||||
print("PASS: six distinct nonblank native roulette frames at draft/spin/landing/result")
|
||||
|
||||
|
||||
def parity():
|
||||
tested = Coff(ROOT / "build/actions/actions-test.obj")
|
||||
shipped = Coff(ROOT / "build/graphics/poker.obj")
|
||||
functions = (("InitNativeWheel3D", 0), ("HandleNativeWheel3D", 0),
|
||||
("RenderNativeWheel3D", 0), ("WheelSettle3D", 0),
|
||||
("WheelAddBet3D", 4), ("WheelBetMultiplier3D", 8),
|
||||
("WheelEscape3D", 0), ("WheelTravel3D", 12),
|
||||
("DrawNativeWheelDisc3D", 20), ("RenderWheelScene3D", 0),
|
||||
("LoadNativeWheelArt3D", 0), ("FreeNativeWheelArt3D", 0),
|
||||
("DrawWheelDigit3D", 20), ("DrawWheelValue3D", 20), ("DrawWheelLabels3D", 20),
|
||||
("AnimateCityPedestrians3D", 0), ("HandleArrival3D", 0))
|
||||
for name, arguments in functions:
|
||||
symbol = f"_{name}@{arguments}"
|
||||
assert tested.signature(symbol) == shipped.signature(symbol), name
|
||||
print("PASS: shipping roulette and street animation procedures match native-tested code")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--assets-only", action="store_true")
|
||||
parser.add_argument("--parity", action="store_true")
|
||||
options = parser.parse_args()
|
||||
assets()
|
||||
if not options.assets_only:
|
||||
captures()
|
||||
if options.parity:
|
||||
parity()
|
||||
64
tools/tests/check_hall_furniture.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
"""Validate tight furniture assets, native captures and tested/shipping code parity."""
|
||||
import argparse
|
||||
import struct
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image
|
||||
from check_card_exit_build import Coff
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
EXPECTED = {
|
||||
"card-table": (320, 208, 1), "roulette-table": (288, 268, 1),
|
||||
"backroom-table": (304, 236, 1), "skill-cabinet": (224, 368, 1),
|
||||
"lounge-chair": (240, 256, 1), "lamp-table": (192, 224, 1),
|
||||
"velvet-rope": (288, 192, 1), "slot-cabinets": (224, 256, 3),
|
||||
}
|
||||
|
||||
|
||||
def assets():
|
||||
for name, (width, height, count) in EXPECTED.items():
|
||||
data = (ROOT / "assets/animations/hall" / (name + "-v5.bin")).read_bytes()
|
||||
assert struct.unpack_from("<4s4I", data) == (
|
||||
b"ANM1", width, height, count, width * height * count * 4), name
|
||||
assert len(data) == 20 + width * height * count * 4
|
||||
for index in range(count):
|
||||
offset = 20 + index * width * height * 4
|
||||
frame = Image.frombytes("RGBA", (width, height),
|
||||
data[offset:offset + width * height * 4], "raw", "BGRA")
|
||||
alpha = frame.getchannel("A")
|
||||
assert set(alpha.tobytes()) == {0, 255}, (name, index)
|
||||
assert alpha.getbbox() == (0, 0, width, height), (name, index)
|
||||
assert len(frame.convert("RGB").getcolors(width * height)) > 100, name
|
||||
print("PASS: eight tight floor-anchored furniture packs; binary alpha and complete bounds")
|
||||
|
||||
|
||||
def captures():
|
||||
for name in ("hall-card-furniture-v5", "hall-skill-furniture-v5", "hall-lounge-v5"):
|
||||
frame = Image.open(ROOT / "build/actions" / (name + ".bmp")).convert("RGB")
|
||||
assert frame.size == (640, 480)
|
||||
assert len(frame.getcolors(640 * 480)) > 1000
|
||||
frame.save(ROOT / "build/actions" / (name + ".png"))
|
||||
print("PASS: native close-up table, complete skill cabinet and lounge snapshots")
|
||||
|
||||
|
||||
def parity():
|
||||
tested = Coff(ROOT / "build/actions/actions-test.obj")
|
||||
shipped = Coff(ROOT / "build/graphics/poker.obj")
|
||||
for name, arguments in (("RenderSprites", 0), ("LoadHallAssets3D", 0),
|
||||
("FreeHallAssets3D", 0), ("RenderHall3D", 0),
|
||||
("CanWalkHall3D", 8)):
|
||||
symbol = f"_{name}@{arguments}"
|
||||
assert tested.signature(symbol) == shipped.signature(symbol), name
|
||||
print("PASS: shipping hall furniture rendering/collision matches native test code")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--assets-only", action="store_true")
|
||||
parser.add_argument("--parity", action="store_true")
|
||||
options = parser.parse_args()
|
||||
assets()
|
||||
if not options.assets_only:
|
||||
captures()
|
||||
if options.parity:
|
||||
parity()
|
||||
|
|
@ -13,8 +13,9 @@ 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') == 8
|
||||
assert interaction.count('call BeginUnavailable3D') == 7
|
||||
assert 'call InitNativeDurak3D' in interaction
|
||||
assert 'call InitNativeSlots3D' in interaction
|
||||
panel = Image.open(OUTPUT / 'unavailable.bmp').convert('RGB')
|
||||
assert panel.size == (640, 480)
|
||||
assert panel.getpixel((110, 190)) == (23, 29, 32)
|
||||
|
|
|
|||
26
tools/tests/check_slot_build.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
"""Require the shipped slot machine to use the same code as the native tests."""
|
||||
from pathlib import Path
|
||||
|
||||
from check_card_exit_build import Coff
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def main():
|
||||
tested = Coff(ROOT / "build/actions/actions-test.obj")
|
||||
shipped = Coff(ROOT / "build/graphics/poker.obj")
|
||||
functions = {"InitNativeSlots3D": 0, "FreeNativeSlots3D": 0,
|
||||
"StartNativeSlots3D": 0, "HandleNativeSlots3D": 0,
|
||||
"RenderNativeSlots3D": 0, "SlotMultiplier3D": 12,
|
||||
"SettleNativeSlots3D": 0, "SlotEscape3D": 0, "SlotExitMouse3D": 0,
|
||||
"SlotReelPosition3D": 4, "DrawSlotReel3D": 4,
|
||||
"DrawSlotSymbol3D": 12, "Trigger3DInteraction": 0,
|
||||
"StartCasino3D": 0, "CardTableEscape3D": 0}
|
||||
for name, size in functions.items():
|
||||
symbol = f"_{name}@{size}"
|
||||
assert tested.signature(symbol) == shipped.signature(symbol), name
|
||||
print("PASS: shipping slot rules, input, reels, exit and renderer match tested MASM code")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
65
tools/tests/check_slot_frames.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
"""Inspect snapshots from the real MASM reel renderer, not a Python simulation."""
|
||||
import hashlib
|
||||
import struct
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageChops
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
OUTPUT = ROOT / "build/actions"
|
||||
NAMES = ["slots-ready", "slots-600", "slots-1799", "slots-1800",
|
||||
"slots-2400", "slots-win", "slots-paytable", "slots-exit"]
|
||||
|
||||
|
||||
def main():
|
||||
packs = ROOT / "assets/animations/slots"
|
||||
raw = (packs / "cabinet-v1.bin").read_bytes()
|
||||
assert struct.unpack_from("<4s4I", raw) == (b"ANM1", 640, 480, 1, 640 * 480 * 4)
|
||||
cabinet = Image.frombytes("RGBA", (640, 480), raw[20:], "raw", "BGRA").convert("RGB")
|
||||
assert set(raw[23::4]) == {255}, "Fast cabinet copy requires fully opaque pixels"
|
||||
symbols = (packs / "symbols-v1.bin").read_bytes()
|
||||
assert struct.unpack_from("<4s4I", symbols) == (b"ANM1", 64, 64, 8, 64 * 64 * 4 * 8)
|
||||
assert len(symbols) == 20 + 64 * 64 * 4 * 8
|
||||
assert set(symbols[23::4]) == {0, 255}
|
||||
stride = 64 * 64 * 4
|
||||
assert len({hashlib.sha256(symbols[20 + index * stride:20 + (index + 1) * stride]).digest()
|
||||
for index in range(8)}) == 8
|
||||
frames = {}
|
||||
for name in NAMES:
|
||||
frame = Image.open(OUTPUT / (name + ".bmp")).convert("RGB")
|
||||
assert frame.size == (640, 480)
|
||||
assert len(frame.getcolors(640 * 480)) > 2000, name
|
||||
frames[name] = frame
|
||||
frame.save(OUTPUT / (name + ".png"))
|
||||
assert len({hashlib.sha256(frame.tobytes()).digest() for frame in frames.values()}) == len(NAMES)
|
||||
# No symbol may cover the reel separators, chrome frame or marquee.
|
||||
for name in NAMES:
|
||||
if name == "slots-paytable":
|
||||
continue
|
||||
difference = ImageChops.difference(frames[name], cabinet)
|
||||
for y in range(100, 272):
|
||||
if 188 <= y < 194:
|
||||
continue # Payline markers and win illumination are intentional.
|
||||
for x in range(170, 477):
|
||||
in_reel = 124 <= y < 260 and any(left <= x < left + 88 for left in (180, 278, 376))
|
||||
if not in_reel:
|
||||
assert difference.getpixel((x, y)) == (0, 0, 0), (name, x, y)
|
||||
first = (180, 124, 268, 260)
|
||||
second = (278, 124, 366, 260)
|
||||
third = (376, 124, 464, 260)
|
||||
assert frames["slots-1800"].crop(first).tobytes() == frames["slots-2400"].crop(first).tobytes()
|
||||
# The gold winning line is the only permitted difference on a stopped drum.
|
||||
for rect in (first, second):
|
||||
left, top, right, bottom = rect
|
||||
for box in ((left, top, right, 188), (left, 194, right, bottom)):
|
||||
assert frames["slots-2400"].crop(box).tobytes() == frames["slots-win"].crop(box).tobytes()
|
||||
assert frames["slots-2400"].crop(third).tobytes() != frames["slots-win"].crop(third).tobytes()
|
||||
contact = Image.new("RGB", (640 * 4, 480 * 2))
|
||||
for index, name in enumerate(NAMES):
|
||||
contact.paste(frames[name], ((index % 4) * 640, (index // 4) * 480))
|
||||
contact.save(OUTPUT / "slots-contact.png")
|
||||
print("PASS: 8 distinct native slot frames; pixel-accurate reel clipping; sequential stops; opaque cabinet and 8 real symbol sprites")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -13,8 +13,10 @@ PROPS = ["bench", "hydrant", "mailbox", "newspaper_box", "bollard",
|
|||
|
||||
|
||||
def main():
|
||||
pixels = struct.unpack("<12I", (OUTPUT / "street-visibility-v5.bin").read_bytes())
|
||||
visibility = dict(zip(PROPS + ["walker_1", "walker_2", "walker_3", "walker_4"], pixels))
|
||||
data = (OUTPUT / "street-visibility-v5.bin").read_bytes()
|
||||
pixels = struct.unpack(f"<{len(data)//4}I", data)
|
||||
assert len(pixels) == 14
|
||||
visibility = dict(zip(PROPS + [f"walker_{i+1}" for i in range(6)], pixels))
|
||||
assert pixels[5] == 0, ('Plants must be removed', visibility)
|
||||
assert min(pixels[:5] + pixels[6:]) >= 128, visibility
|
||||
names = [f"street-v5-{index}" for index in range(6)] + ["street-v5-door"]
|
||||
|
|
@ -35,7 +37,7 @@ def main():
|
|||
(OUTPUT / "street-v5-qa.json").write_text(
|
||||
json.dumps({"visible_pixels": visibility, "native_frames": frames}, indent=2),
|
||||
encoding="ascii")
|
||||
print("PASS: two world-geometry benches, six other street prop types, four walkers; no plants;")
|
||||
print("PASS: two world-geometry benches, six other street prop types, six outdoor walkers; no plants;")
|
||||
print("seven distinct native route snapshots; " + json.dumps(visibility))
|
||||
|
||||
|
||||
|
|
|
|||
200
tools/tests/coin_detail_test.inc
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
.data
|
||||
coinDetailBmpHeader3D db 42h,4Dh
|
||||
dd 512054
|
||||
dw 0,0
|
||||
dd 54,40,320,-400
|
||||
dw 1,32
|
||||
dd 0,512000,0,0,0,0
|
||||
coinDetailCapture0 db "build\actions\coin-detail-idle.bmp",0
|
||||
coinDetailCapture1 db "build\actions\coin-detail-air.bmp",0
|
||||
coinDetailCapture2 db "build\actions\coin-detail-heads.bmp",0
|
||||
coinDetailCapture3 db "build\actions\coin-detail-tails.bmp",0
|
||||
coinDetailCapture4 db "build\actions\coin-detail-loss.bmp",0
|
||||
coinDetailCaptures3D dd OFFSET coinDetailCapture0,OFFSET coinDetailCapture1,OFFSET coinDetailCapture2,OFFSET coinDetailCapture3,OFFSET coinDetailCapture4
|
||||
.code
|
||||
RunCoinDetailWindowTest3D PROC uses ebx esi edi
|
||||
local before:CoinDetailRect3D,after:CoinDetailRect3D,panel:CoinDetailRect3D,message:C3D_MSG
|
||||
invoke GetWindowRect,h3DWnd,ADDR before
|
||||
call OpenCoinDetail3D
|
||||
cmp coinDetailWnd3D,0
|
||||
je detail_window_test_fail
|
||||
mov ebx,coinDetailWnd3D
|
||||
call OpenCoinDetail3D
|
||||
cmp coinDetailWnd3D,ebx
|
||||
jne detail_window_test_fail
|
||||
invoke GetWindow,ebx,4
|
||||
cmp eax,h3DWnd
|
||||
jne detail_window_test_fail
|
||||
invoke IsWindowVisible,ebx
|
||||
test eax,eax
|
||||
jnz detail_window_test_fail
|
||||
call LayoutCoinDetail3D
|
||||
invoke GetWindowRect,ebx,ADDR panel
|
||||
invoke GetWindowRect,h3DWnd,ADDR after
|
||||
mov eax,after.right
|
||||
add eax,8
|
||||
cmp panel.left,eax
|
||||
jne detail_window_test_fail
|
||||
mov eax,panel.right
|
||||
cmp eax,coinDetailMonitor3D[28]
|
||||
jg detail_window_test_fail
|
||||
mov eax,panel.top
|
||||
cmp eax,coinDetailMonitor3D[24]
|
||||
jl detail_window_test_fail
|
||||
mov eax,panel.bottom
|
||||
cmp eax,coinDetailMonitor3D[32]
|
||||
jg detail_window_test_fail
|
||||
call CloseCoinDetail3D
|
||||
cmp coinDetailWnd3D,0
|
||||
jne detail_window_test_fail
|
||||
invoke IsWindow,ebx
|
||||
test eax,eax
|
||||
jnz detail_window_test_fail
|
||||
invoke GetWindowRect,h3DWnd,ADDR after
|
||||
lea esi,before
|
||||
lea edi,after
|
||||
mov ecx,4
|
||||
repe cmpsd
|
||||
jne detail_window_test_fail
|
||||
invoke PeekMessageA,ADDR message,0,WM_QUIT,WM_QUIT,0
|
||||
test eax,eax
|
||||
jnz detail_window_test_fail
|
||||
; F11 preserves a live detail window without saving its temporary resize.
|
||||
call OpenCoinDetail3D
|
||||
call ToggleFullscreen3D
|
||||
cmp fullscreen3D,0
|
||||
jne detail_window_test_fail
|
||||
cmp coinDetailWnd3D,0
|
||||
je detail_window_test_fail
|
||||
call ToggleFullscreen3D
|
||||
cmp fullscreen3D,1
|
||||
jne detail_window_test_fail
|
||||
call CloseCoinDetail3D
|
||||
invoke GetWindowRect,h3DWnd,ADDR after
|
||||
lea esi,before
|
||||
lea edi,after
|
||||
mov ecx,4
|
||||
repe cmpsd
|
||||
jne detail_window_test_fail
|
||||
; Closing the preview must not undo an explicit later move of the owner.
|
||||
call OpenCoinDetail3D
|
||||
invoke SetWindowPos,h3DWnd,0,coinDetailMonitor3D[20],coinDetailMonitor3D[24],600,300,14h
|
||||
invoke GetWindowRect,h3DWnd,ADDR panel
|
||||
call CloseCoinDetail3D
|
||||
invoke GetWindowRect,h3DWnd,ADDR after
|
||||
lea esi,panel
|
||||
lea edi,after
|
||||
mov ecx,4
|
||||
repe cmpsd
|
||||
jne detail_window_test_fail
|
||||
mov eax,before.right
|
||||
sub eax,before.left
|
||||
mov edx,before.bottom
|
||||
sub edx,before.top
|
||||
invoke SetWindowPos,h3DWnd,0,before.left,before.top,eax,edx,14h
|
||||
xor eax,eax
|
||||
ret
|
||||
detail_window_test_fail:
|
||||
mov eax,8601
|
||||
ret
|
||||
RunCoinDetailWindowTest3D ENDP
|
||||
|
||||
WriteCoinDetailSnapshot3D PROC uses ebx path:DWORD
|
||||
local count:DWORD
|
||||
invoke CreateFileA,path,40000000h,0,0,2,80h,0
|
||||
cmp eax,-1
|
||||
je detail_snapshot_fail
|
||||
mov ebx,eax
|
||||
invoke WriteFile,ebx,OFFSET coinDetailBmpHeader3D,54,ADDR count,0
|
||||
invoke WriteFile,ebx,OFFSET coinDetailBuffer3D,512000,ADDR count,0
|
||||
invoke CloseHandle,ebx
|
||||
cmp count,512000
|
||||
jne detail_snapshot_fail
|
||||
mov eax,1
|
||||
ret
|
||||
detail_snapshot_fail:
|
||||
xor eax,eax
|
||||
ret
|
||||
WriteCoinDetailSnapshot3D ENDP
|
||||
|
||||
RunCoinDetailRenderTest3D PROC uses ebx esi edi
|
||||
local oldBank:DWORD,oldSeed:DWORD,oldTimer:DWORD,oldMode:DWORD,oldState:DWORD,oldChoice:DWORD,oldResult:DWORD
|
||||
mov eax,bankroll
|
||||
mov oldBank,eax
|
||||
mov eax,rngSeed3D
|
||||
mov oldSeed,eax
|
||||
mov eax,coin3d_timer
|
||||
mov oldTimer,eax
|
||||
mov eax,engineMode
|
||||
mov oldMode,eax
|
||||
mov eax,coin3d_state
|
||||
mov oldState,eax
|
||||
mov eax,coin3d_choice
|
||||
mov oldChoice,eax
|
||||
mov eax,coin3d_result
|
||||
mov oldResult,eax
|
||||
mov edi,OFFSET screenBuffer
|
||||
mov ecx,SCREEN_SIZE
|
||||
mov eax,00123456h
|
||||
rep stosd
|
||||
mov engineMode,MODE_COIN
|
||||
mov coin3d_choice,1
|
||||
mov coin3d_result,1
|
||||
mov coinStartPhase3D,96
|
||||
xor ebx,ebx
|
||||
detail_render_test_frame:
|
||||
mov coin3d_state,COIN_IDLE
|
||||
mov coin3d_timer,0
|
||||
test ebx,ebx
|
||||
jz detail_render_test_capture
|
||||
mov coin3d_state,COIN_TOSS
|
||||
mov coin3d_timer,600
|
||||
cmp ebx,1
|
||||
je detail_render_test_capture
|
||||
mov coin3d_state,COIN_RESULT
|
||||
mov coin3d_timer,COIN_TOTAL_MS
|
||||
mov coin3d_result,1
|
||||
cmp ebx,2
|
||||
je detail_render_test_capture
|
||||
mov coin3d_result,2
|
||||
mov coin3d_choice,2
|
||||
cmp ebx,3
|
||||
je detail_render_test_capture
|
||||
mov coin3d_choice,1
|
||||
detail_render_test_capture:
|
||||
call RenderCoinDetail3D
|
||||
mov eax,oldBank
|
||||
cmp bankroll,eax
|
||||
jne detail_render_test_fail
|
||||
mov eax,oldSeed
|
||||
cmp rngSeed3D,eax
|
||||
jne detail_render_test_fail
|
||||
mov esi,OFFSET screenBuffer
|
||||
mov ecx,SCREEN_SIZE
|
||||
detail_render_test_scene:
|
||||
cmp DWORD PTR [esi],00123456h
|
||||
jne detail_render_test_fail
|
||||
add esi,4
|
||||
loop detail_render_test_scene
|
||||
invoke WriteCoinDetailSnapshot3D,coinDetailCaptures3D[ebx*4]
|
||||
test eax,eax
|
||||
jz detail_render_test_fail
|
||||
inc ebx
|
||||
cmp ebx,5
|
||||
jb detail_render_test_frame
|
||||
mov eax,oldTimer
|
||||
mov coin3d_timer,eax
|
||||
mov eax,oldMode
|
||||
mov engineMode,eax
|
||||
mov eax,oldState
|
||||
mov coin3d_state,eax
|
||||
mov eax,oldChoice
|
||||
mov coin3d_choice,eax
|
||||
mov eax,oldResult
|
||||
mov coin3d_result,eax
|
||||
xor eax,eax
|
||||
ret
|
||||
detail_render_test_fail:
|
||||
mov eax,8602
|
||||
ret
|
||||
RunCoinDetailRenderTest3D ENDP
|
||||
367
tools/tests/coin_test.inc
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
.data
|
||||
coinTestStage3D dd 0
|
||||
coinTestRates3D dd 8,16,33,250
|
||||
coinTestTimes3D dd 0,180,300,420,600,900,1020,1110,1700
|
||||
coinTest0 db "build\actions\coin-idle.bmp",0
|
||||
coinTest1 db "build\actions\coin-hold.bmp",0
|
||||
coinTest2 db "build\actions\coin-release.bmp",0
|
||||
coinTest3 db "build\actions\coin-air.bmp",0
|
||||
coinTest4 db "build\actions\coin-apex.bmp",0
|
||||
coinTest5 db "build\actions\coin-descent.bmp",0
|
||||
coinTest6 db "build\actions\coin-land.bmp",0
|
||||
coinTest7 db "build\actions\coin-bounce.bmp",0
|
||||
coinTest8 db "build\actions\coin-result.bmp",0
|
||||
coinTest9 db "build\actions\coin-tails.bmp",0
|
||||
coinTestPaths3D dd OFFSET coinTest0,OFFSET coinTest1,OFFSET coinTest2
|
||||
dd OFFSET coinTest3,OFFSET coinTest4,OFFSET coinTest5
|
||||
dd OFFSET coinTest6,OFFSET coinTest7,OFFSET coinTest8
|
||||
.code
|
||||
RunCoinTest3D PROC uses ebx esi edi
|
||||
local oldBank:DWORD,oldSeed:DWORD,oldMode:DWORD,oldDelta:DWORD
|
||||
local expected:DWORD,seedSnapshot:DWORD,ticks:DWORD,total:DWORD,iterations:DWORD
|
||||
local pointer:DWORD,previousX:DWORD,previousY:DWORD
|
||||
mov eax,bankroll
|
||||
mov oldBank,eax
|
||||
mov eax,rngSeed3D
|
||||
mov oldSeed,eax
|
||||
mov eax,engineMode
|
||||
mov oldMode,eax
|
||||
mov eax,deltaTime3D
|
||||
mov oldDelta,eax
|
||||
call ClearKeys3D
|
||||
mov mouseClick3D,0
|
||||
mov bankroll,100000
|
||||
mov coinTestStage3D,1
|
||||
mov engineMode,MODE_WALK
|
||||
mov interactTargetId,INTERACT_COIN
|
||||
call Trigger3DInteraction
|
||||
cmp engineMode,MODE_COIN
|
||||
jne coin_test_fail
|
||||
cmp coinArtReady3D,1
|
||||
jne coin_test_fail
|
||||
cmp coinHandsArt3D.frames,16
|
||||
jne coin_test_fail
|
||||
mov eax,coinTableArt3D.pixels
|
||||
mov pointer,eax
|
||||
call InitCoinGame
|
||||
mov eax,pointer
|
||||
cmp coinTableArt3D.pixels,eax
|
||||
jne coin_test_fail
|
||||
; Missing packs and insufficient funds cannot consume a wager or RNG.
|
||||
mov coinTestStage3D,2
|
||||
call FreeNativeCoinArt3D
|
||||
mov BYTE PTR coinHandsPath3D,'!'
|
||||
call InitCoinGame
|
||||
mov BYTE PTR coinHandsPath3D,'a'
|
||||
test eax,eax
|
||||
jnz coin_test_fail
|
||||
cmp coinArtReady3D,0
|
||||
jne coin_test_fail
|
||||
cmp coinTableArt3D.pixels,0
|
||||
jne coin_test_fail
|
||||
mov eax,rngSeed3D
|
||||
mov seedSnapshot,eax
|
||||
mov pressedKeys3D[20h],1
|
||||
call HandleCoinInput
|
||||
cmp bankroll,100000
|
||||
jne coin_test_fail
|
||||
mov eax,seedSnapshot
|
||||
cmp rngSeed3D,eax
|
||||
jne coin_test_fail
|
||||
call InitCoinGame
|
||||
test eax,eax
|
||||
jz coin_test_fail
|
||||
mov bankroll,49
|
||||
mov coin3d_bet,50
|
||||
mov pressedKeys3D[20h],1
|
||||
call HandleCoinInput
|
||||
cmp bankroll,49
|
||||
jne coin_test_fail
|
||||
cmp coinError3D,1
|
||||
jne coin_test_fail
|
||||
cmp coin3d_state,COIN_IDLE
|
||||
jne coin_test_fail
|
||||
mov eax,seedSnapshot
|
||||
cmp rngSeed3D,eax
|
||||
jne coin_test_fail
|
||||
; Bounds, face choices and edge-consumed controls use the real handler.
|
||||
mov coinTestStage3D,3
|
||||
mov pressedKeys3D[53h],1
|
||||
call HandleCoinInput
|
||||
cmp coin3d_bet,50
|
||||
jne coin_test_fail
|
||||
mov coin3d_bet,5000
|
||||
mov pressedKeys3D[57h],1
|
||||
call HandleCoinInput
|
||||
cmp coin3d_bet,5000
|
||||
jne coin_test_fail
|
||||
mov coin3d_bet,100
|
||||
mov mouseX3D,124
|
||||
mov mouseY3D,204
|
||||
mov mouseClick3D,1
|
||||
call HandleCoinInput
|
||||
cmp coin3d_bet,50
|
||||
jne coin_test_fail
|
||||
mov mouseX3D,148
|
||||
mov mouseClick3D,1
|
||||
call HandleCoinInput
|
||||
cmp coin3d_bet,100
|
||||
jne coin_test_fail
|
||||
call HandleCoinInput
|
||||
cmp coin3d_bet,100
|
||||
jne coin_test_fail
|
||||
mov mouseX3D,150
|
||||
mov mouseY3D,226
|
||||
mov mouseClick3D,1
|
||||
call HandleCoinInput
|
||||
cmp coin3d_choice,2
|
||||
jne coin_test_fail
|
||||
mov pressedKeys3D[31h],1
|
||||
call HandleCoinInput
|
||||
cmp coin3d_choice,1
|
||||
jne coin_test_fail
|
||||
; Five hundred paid flips, both outcomes and both choices, four frame rates.
|
||||
mov coinTestStage3D,4
|
||||
mov iterations,500
|
||||
coin_test_round:
|
||||
mov bankroll,100000
|
||||
mov coin3d_state,COIN_IDLE
|
||||
mov coin3d_timer,0
|
||||
mov coin3d_bet,100
|
||||
mov engineMode,MODE_COIN
|
||||
mov eax,iterations
|
||||
and eax,1
|
||||
inc eax
|
||||
mov coin3d_choice,eax
|
||||
mov pressedKeys3D[20h],1
|
||||
call HandleCoinInput
|
||||
cmp coin3d_state,COIN_TOSS
|
||||
jne coin_test_fail
|
||||
cmp bankroll,99900
|
||||
jne coin_test_fail
|
||||
mov eax,iterations
|
||||
shr eax,1
|
||||
and eax,1
|
||||
inc eax
|
||||
mov coin3d_result,eax
|
||||
mov expected,99900
|
||||
cmp eax,coin3d_choice
|
||||
jne @F
|
||||
mov expected,100100
|
||||
@@:
|
||||
mov eax,rngSeed3D
|
||||
mov seedSnapshot,eax
|
||||
mov eax,iterations
|
||||
and eax,3
|
||||
mov eax,coinTestRates3D[eax*4]
|
||||
mov deltaTime3D,eax
|
||||
mov ticks,0
|
||||
mov total,0
|
||||
; Half the rounds request Escape before the toss completes.
|
||||
test iterations,1
|
||||
jz coin_test_tick
|
||||
call CardTableEscape3D
|
||||
cmp eax,1
|
||||
jne coin_test_fail
|
||||
cmp engineMode,MODE_COIN
|
||||
jne coin_test_fail
|
||||
cmp coinExitQueued3D,1
|
||||
jne coin_test_fail
|
||||
coin_test_tick:
|
||||
call HandleCoinInput
|
||||
inc ticks
|
||||
mov eax,deltaTime3D
|
||||
add total,eax
|
||||
cmp ticks,326
|
||||
ja coin_test_fail
|
||||
cmp coin3d_state,COIN_TOSS
|
||||
je coin_test_tick
|
||||
cmp coin3d_state,COIN_RESULT
|
||||
jne coin_test_fail
|
||||
cmp coin3d_timer,COIN_TOTAL_MS
|
||||
jne coin_test_fail
|
||||
cmp total,COIN_TOTAL_MS
|
||||
jb coin_test_fail
|
||||
mov eax,COIN_TOTAL_MS
|
||||
add eax,deltaTime3D
|
||||
cmp total,eax
|
||||
jae coin_test_fail
|
||||
mov eax,expected
|
||||
cmp bankroll,eax
|
||||
jne coin_test_fail
|
||||
call CoinSettle3D
|
||||
mov eax,expected
|
||||
cmp bankroll,eax
|
||||
jne coin_test_fail
|
||||
mov eax,seedSnapshot
|
||||
cmp rngSeed3D,eax
|
||||
jne coin_test_fail
|
||||
test iterations,1
|
||||
jz @F
|
||||
cmp engineMode,MODE_WALK
|
||||
jne coin_test_fail
|
||||
@@:
|
||||
dec iterations
|
||||
jnz coin_test_round
|
||||
; Exit during every animation phase settles the paid bet before leaving.
|
||||
mov coinTestStage3D,5
|
||||
xor esi,esi
|
||||
coin_test_exit_phase:
|
||||
mov coin3d_state,COIN_TOSS
|
||||
mov coin3d_choice,1
|
||||
mov coin3d_result,1
|
||||
mov coin3d_bet,100
|
||||
mov bankroll,99900
|
||||
mov coinExitQueued3D,0
|
||||
mov engineMode,MODE_COIN
|
||||
mov eax,coinTestTimes3D[esi*4]
|
||||
cmp eax,COIN_TOTAL_MS
|
||||
jb @F
|
||||
dec eax
|
||||
@@:
|
||||
mov coin3d_timer,eax
|
||||
mov mouseClick3D,1
|
||||
mov mouseX3D,280
|
||||
mov mouseY3D,9
|
||||
mov deltaTime3D,16
|
||||
call HandleCoinInput
|
||||
mov deltaTime3D,COIN_TOTAL_MS
|
||||
cmp engineMode,MODE_WALK
|
||||
je @F
|
||||
call HandleCoinInput
|
||||
@@:
|
||||
cmp engineMode,MODE_WALK
|
||||
jne coin_test_fail
|
||||
cmp bankroll,100100
|
||||
jne coin_test_fail
|
||||
inc esi
|
||||
cmp esi,9
|
||||
jb coin_test_exit_phase
|
||||
; Capture the actual renderer; rendering cannot move the simulation/RNG.
|
||||
mov coinTestStage3D,6
|
||||
mov engineMode,MODE_COIN
|
||||
mov coin3d_choice,1
|
||||
mov coin3d_result,1
|
||||
mov coinStartPhase3D,96
|
||||
mov coin3d_win,200
|
||||
mov coinExitQueued3D,0
|
||||
mov eax,rngSeed3D
|
||||
mov seedSnapshot,eax
|
||||
xor esi,esi
|
||||
coin_test_snapshot:
|
||||
mov coin3d_state,COIN_TOSS
|
||||
test esi,esi
|
||||
jnz @F
|
||||
mov coin3d_state,COIN_IDLE
|
||||
@@:
|
||||
cmp esi,8
|
||||
jne @F
|
||||
mov coin3d_state,COIN_RESULT
|
||||
@@:
|
||||
mov eax,coinTestTimes3D[esi*4]
|
||||
mov coin3d_timer,eax
|
||||
call RenderCoinGame
|
||||
mov eax,coinTestTimes3D[esi*4]
|
||||
cmp coin3d_timer,eax
|
||||
jne coin_test_fail
|
||||
cmp bankroll,100100
|
||||
jne coin_test_fail
|
||||
mov eax,seedSnapshot
|
||||
cmp rngSeed3D,eax
|
||||
jne coin_test_fail
|
||||
invoke WriteActionSnapshot3D,coinTestPaths3D[esi*4]
|
||||
test eax,eax
|
||||
jz coin_test_fail
|
||||
inc esi
|
||||
cmp esi,9
|
||||
jb coin_test_snapshot
|
||||
mov coin3d_result,2
|
||||
mov coin3d_choice,2
|
||||
call RenderCoinGame
|
||||
cmp coinFace3D,1
|
||||
jne coin_test_fail
|
||||
invoke WriteActionSnapshot3D,OFFSET coinTest9
|
||||
mov coin3d_choice,1
|
||||
; Coin position remains continuous across release, flight and bounces.
|
||||
mov coin3d_state,COIN_TOSS
|
||||
xor esi,esi
|
||||
invoke CoinPose3D,0
|
||||
mov eax,coinX3D
|
||||
mov previousX,eax
|
||||
mov eax,coinY3D
|
||||
mov previousY,eax
|
||||
coin_test_pose:
|
||||
invoke CoinPose3D,esi
|
||||
mov eax,coinX3D
|
||||
sub eax,previousX
|
||||
test eax,eax
|
||||
jns @F
|
||||
neg eax
|
||||
@@:
|
||||
cmp eax,2
|
||||
ja coin_test_fail
|
||||
mov eax,coinY3D
|
||||
sub eax,previousY
|
||||
test eax,eax
|
||||
jns @F
|
||||
neg eax
|
||||
@@:
|
||||
cmp eax,2
|
||||
ja coin_test_fail
|
||||
mov eax,coinX3D
|
||||
mov previousX,eax
|
||||
mov eax,coinY3D
|
||||
mov previousY,eax
|
||||
cmp coinWidth3D,32
|
||||
jb coin_test_fail
|
||||
cmp coinHeight3D,3
|
||||
jb coin_test_fail
|
||||
inc esi
|
||||
cmp esi,COIN_TOTAL_MS
|
||||
jbe coin_test_pose
|
||||
mov coin3d_state,COIN_RESULT
|
||||
mov mouseClick3D,1
|
||||
mov mouseX3D,250
|
||||
mov mouseY3D,226
|
||||
call HandleCoinInput
|
||||
cmp coin3d_state,COIN_IDLE
|
||||
jne coin_test_fail
|
||||
cmp bankroll,100100
|
||||
jne coin_test_fail
|
||||
call HandleCoinInput
|
||||
cmp coin3d_state,COIN_IDLE
|
||||
jne coin_test_fail
|
||||
mov bankroll,999999999
|
||||
mov coin3d_state,COIN_TOSS
|
||||
mov coin3d_bet,5000
|
||||
mov coin3d_choice,1
|
||||
mov coin3d_result,1
|
||||
call CoinSettle3D
|
||||
call CoinSettle3D
|
||||
cmp bankroll,1000000000
|
||||
jne coin_test_fail
|
||||
call CoinEscape3D
|
||||
cmp engineMode,MODE_WALK
|
||||
jne coin_test_fail
|
||||
mov eax,oldBank
|
||||
mov bankroll,eax
|
||||
mov eax,oldSeed
|
||||
mov rngSeed3D,eax
|
||||
mov eax,oldMode
|
||||
mov engineMode,eax
|
||||
mov eax,oldDelta
|
||||
mov deltaTime3D,eax
|
||||
call ClearKeys3D
|
||||
call RunCoinDetailRenderTest3D
|
||||
test eax,eax
|
||||
jz @F
|
||||
ret
|
||||
@@:
|
||||
call FreeNativeCoinArt3D
|
||||
xor eax,eax
|
||||
ret
|
||||
coin_test_fail:
|
||||
mov eax,coinTestStage3D
|
||||
add eax,8100
|
||||
ret
|
||||
RunCoinTest3D ENDP
|
||||
94
tools/tests/diagnose_wheel_assert.py
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
"""Offline assertion breakpoint in the native test executable, not game code."""
|
||||
import ctypes as c
|
||||
import struct
|
||||
|
||||
from capstone import Cs, CS_ARCH_X86, CS_MODE_32
|
||||
from debug_native_crash import K, ROOT, Startup, Process, Event
|
||||
from check_card_exit_build import Coff
|
||||
|
||||
|
||||
def main():
|
||||
obj = Coff(ROOT / "build/actions/actions-test.obj")
|
||||
sec, start = obj.functions["_RunWheelSceneTest3D@0"]
|
||||
raw, size, _ = obj.sections[sec]
|
||||
end = min(v for s, v in obj.functions.values() if s == sec and v > start)
|
||||
instructions = list(Cs(CS_ARCH_X86, CS_MODE_32).disasm(obj.data[raw + start:raw + end], start))
|
||||
trap_offset = instructions[-6].address
|
||||
assert instructions[-6].mnemonic == "mov"
|
||||
symbols = {}
|
||||
_, _, _, table, total, _, _ = struct.unpack_from("<HHIIIHH", obj.data)
|
||||
index = 0
|
||||
while index < total:
|
||||
value, section, _, _, aux = struct.unpack_from("<IhHBB", obj.data, table + index * 18 + 8)
|
||||
if section == 2:
|
||||
symbols[obj.symbols[index]] = value
|
||||
index += aux + 1
|
||||
pe = (ROOT / "build/actions/actions-test.exe").read_bytes()
|
||||
header = struct.unpack_from("<I", pe, 60)[0]
|
||||
count = struct.unpack_from("<H", pe, header + 6)[0]
|
||||
opt = struct.unpack_from("<H", pe, header + 20)[0]
|
||||
sections = header + 24 + opt
|
||||
data_rva = None
|
||||
for i in range(count):
|
||||
at = sections + i * 40
|
||||
if pe[at:at + 8].rstrip(b"\0") == b".data":
|
||||
data_rva = struct.unpack_from("<I", pe, at + 12)[0]
|
||||
assert data_rva
|
||||
K.WriteProcessMemory.argtypes = [c.c_void_p, c.c_void_p, c.c_void_p, c.c_size_t, c.c_void_p]
|
||||
K.TerminateProcess.argtypes = [c.c_void_p, c.c_uint32]
|
||||
start_info, process = Startup(), Process()
|
||||
start_info.cb, start_info.flags, start_info.show = c.sizeof(start_info), 1, 0
|
||||
executable = str(ROOT / "build/actions/actions-test.exe")
|
||||
command = c.create_unicode_buffer('"' + executable + '"')
|
||||
if not K.CreateProcessW(executable, command, None, None, False, 3, None,
|
||||
str(ROOT), c.byref(start_info), c.byref(process)):
|
||||
raise c.WinError(c.get_last_error())
|
||||
base = trap = 0
|
||||
|
||||
def memory(address, size):
|
||||
buffer, read = c.create_string_buffer(size), c.c_size_t()
|
||||
assert K.ReadProcessMemory(process.process, address, buffer, size, c.byref(read))
|
||||
return buffer.raw[:read.value]
|
||||
|
||||
while True:
|
||||
event = Event()
|
||||
assert K.WaitForDebugEvent(c.byref(event), 120000)
|
||||
data, status = bytes(event.data), 0x10002
|
||||
if event.code == 3:
|
||||
base = struct.unpack_from("<Q", data, 24)[0]
|
||||
trap = base + 0x1000 + trap_offset
|
||||
assert K.WriteProcessMemory(process.process, trap, b"\xcc", 1, None)
|
||||
elif event.code == 1:
|
||||
exception = struct.unpack_from("<I", data)[0]
|
||||
address = struct.unpack_from("<Q", data, 16)[0]
|
||||
if exception in (0x80000003, 0x4000001F) and address == trap:
|
||||
thread = K.OpenThread(0x48, False, event.tid)
|
||||
context = c.create_string_buffer(716)
|
||||
struct.pack_into("<I", context, 0, 0x10007)
|
||||
assert K.Wow64GetThreadContext(thread, context)
|
||||
regs = dict(zip(("edi", "esi", "ebx", "edx", "ecx", "eax", "ebp", "eip", "cs", "flags", "esp"),
|
||||
struct.unpack_from("<11I", context, 156)))
|
||||
print("ASSERTION REGISTERS:", regs, flush=True)
|
||||
print("LOCALS:", struct.unpack("<7I", memory(regs["ebp"] - 28, 28)), flush=True)
|
||||
for name in ("wheelArtReady3D", "wheelStake3D", "wheelReturn3D", "wheelResult3D",
|
||||
"wheelResultSlot3D", "wheelBallAngle3D", "bankroll", "rngSeed3D", "roulState"):
|
||||
print(name, struct.unpack("<I", memory(base + data_rva + symbols[name], 4))[0], flush=True)
|
||||
K.CloseHandle(thread)
|
||||
K.TerminateProcess(process.process, 1)
|
||||
elif exception not in (0x80000003, 0x4000001F):
|
||||
status = 0x80010001
|
||||
elif event.code == 5:
|
||||
print("PROCESS EXIT:", struct.unpack_from("<I", data)[0], flush=True)
|
||||
K.ContinueDebugEvent(event.pid, event.tid, status)
|
||||
break
|
||||
elif event.code == 6:
|
||||
handle = struct.unpack_from("<Q", data)[0]
|
||||
if handle:
|
||||
K.CloseHandle(handle)
|
||||
K.ContinueDebugEvent(event.pid, event.tid, status)
|
||||
K.CloseHandle(process.thread)
|
||||
K.CloseHandle(process.process)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
80
tools/tests/hall_furniture_test.inc
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
.data
|
||||
hallFurnitureCardShot3D db "build\actions\hall-card-furniture-v5.bmp",0
|
||||
hallFurnitureSkillShot3D db "build\actions\hall-skill-furniture-v5.bmp",0
|
||||
hallFurnitureLoungeShot3D db "build\actions\hall-lounge-v5.bmp",0
|
||||
.code
|
||||
TestHallFurniture3D PROC uses ebx esi edi
|
||||
cmp hallCardFurniture3D.imageWidth,320
|
||||
jne furniture_test_fail
|
||||
cmp hallCardFurniture3D.height,208
|
||||
jne furniture_test_fail
|
||||
cmp hallSkillFurniture3D.imageWidth,224
|
||||
jne furniture_test_fail
|
||||
cmp hallSkillFurniture3D.height,368
|
||||
jne furniture_test_fail
|
||||
cmp hallSlotFurniture3D.frames,3
|
||||
jne furniture_test_fail
|
||||
cmp hallStationPacks3D[12*4],OFFSET hallSkillFurniture3D
|
||||
jne furniture_test_fail
|
||||
cmp hallSpriteHeights3D[12*4],FP_1*9/5
|
||||
jne furniture_test_fail
|
||||
; New decor has floor anchors, valid rooms, collision and preserved walking routes.
|
||||
xor esi,esi
|
||||
furniture_test_positions:
|
||||
imul ebx,esi,SIZEOF CityProp3D
|
||||
cmp hallLoungeDecor3D[ebx].groundZ,0
|
||||
jne furniture_test_fail
|
||||
mov eax,hallLoungeDecor3D[ebx].posX
|
||||
sar eax,16
|
||||
mov edx,hallLoungeDecor3D[ebx].posY
|
||||
sar edx,16
|
||||
shl edx,5
|
||||
add eax,edx
|
||||
cmp casinoMap[eax],0
|
||||
jne furniture_test_fail
|
||||
invoke CanWalk3D,hallLoungeDecor3D[ebx].posX,hallLoungeDecor3D[ebx].posY
|
||||
test eax,eax
|
||||
jnz furniture_test_fail
|
||||
inc esi
|
||||
cmp esi,HALL_DECOR_COUNT
|
||||
jb furniture_test_positions
|
||||
invoke CanWalk3D,16*FP_1,18*FP_1
|
||||
cmp eax,1
|
||||
jne furniture_test_fail
|
||||
mov engineMode,MODE_WALK
|
||||
mov viewHorizon3D,HALF_H
|
||||
mov viewEye3D,FP_1*17/20
|
||||
mov playerAngle,384
|
||||
mov playerX,12*FP_1+FP_HALF
|
||||
mov playerY,11*FP_1
|
||||
call UpdateCamera3D
|
||||
call RenderCeilingAndFloor
|
||||
call RenderWalls
|
||||
call PrepareCityDepth3D
|
||||
call RenderSprites
|
||||
call RenderHall3D
|
||||
invoke WriteActionSnapshot3D,OFFSET hallFurnitureCardShot3D
|
||||
mov playerX,18*FP_1
|
||||
mov playerY,18*FP_1
|
||||
call UpdateCamera3D
|
||||
call RenderCeilingAndFloor
|
||||
call RenderWalls
|
||||
call PrepareCityDepth3D
|
||||
call RenderSprites
|
||||
call RenderHall3D
|
||||
invoke WriteActionSnapshot3D,OFFSET hallFurnitureSkillShot3D
|
||||
mov playerX,14*FP_1
|
||||
mov playerY,22*FP_1
|
||||
call UpdateCamera3D
|
||||
call RenderCeilingAndFloor
|
||||
call RenderWalls
|
||||
call PrepareCityDepth3D
|
||||
call RenderSprites
|
||||
call RenderHall3D
|
||||
invoke WriteActionSnapshot3D,OFFSET hallFurnitureLoungeShot3D
|
||||
mov eax,1
|
||||
ret
|
||||
furniture_test_fail:
|
||||
xor eax,eax
|
||||
ret
|
||||
TestHallFurniture3D ENDP
|
||||
|
|
@ -87,6 +87,8 @@ surface_test_fail:
|
|||
TestHallSurface3D ENDP
|
||||
|
||||
include tools\tests\world_regression.inc
|
||||
include tools\tests\hall_furniture_test.inc
|
||||
include tools\tests\wheel_scene_test.inc
|
||||
|
||||
RunHallTest3D PROC uses ebx esi edi
|
||||
local oldBank:DWORD,oldSeed:DWORD,endX:DWORD,endV:DWORD
|
||||
|
|
@ -114,6 +116,9 @@ RunHallTest3D PROC uses ebx esi edi
|
|||
jne hall_test_fail
|
||||
cmp hallDecorPack3D.frames, 6
|
||||
jne hall_test_fail
|
||||
call TestHallFurniture3D
|
||||
cmp eax,1
|
||||
jne hall_test_fail
|
||||
call TestHallSurface3D
|
||||
cmp eax, 1
|
||||
jne hall_test_fail
|
||||
|
|
@ -420,6 +425,9 @@ hall_test_friction:
|
|||
call RenderCityArrival3D
|
||||
invoke WriteActionSnapshot3D,OFFSET hallTestGuards3D
|
||||
mov hallTestStage3D, 77
|
||||
call RunWheelSceneTest3D
|
||||
test eax,eax
|
||||
jnz hall_test_fail
|
||||
call RunWorldRegression3D
|
||||
test eax, eax
|
||||
jz hall_test_fail
|
||||
|
|
|
|||
423
tools/tests/slots_test.inc
Normal file
|
|
@ -0,0 +1,423 @@
|
|||
.data
|
||||
slotsTestStage3D dd 0
|
||||
slotsTest0 db "build\actions\slots-ready.bmp",0
|
||||
slotsTest1 db "build\actions\slots-600.bmp",0
|
||||
slotsTest2 db "build\actions\slots-1799.bmp",0
|
||||
slotsTest3 db "build\actions\slots-1800.bmp",0
|
||||
slotsTest4 db "build\actions\slots-2400.bmp",0
|
||||
slotsTest5 db "build\actions\slots-win.bmp",0
|
||||
slotsTest6 db "build\actions\slots-paytable.bmp",0
|
||||
slotsTest7 db "build\actions\slots-exit.bmp",0
|
||||
slotsTestTimes dd 600,1799,1800,2400
|
||||
slotsTestPaths dd OFFSET slotsTest1,OFFSET slotsTest2,OFFSET slotsTest3,OFFSET slotsTest4
|
||||
slotsTestRates dd 16,33,50,250
|
||||
.code
|
||||
RunSlotsTest3D PROC uses ebx esi edi
|
||||
local oldBank:DWORD,oldMode:DWORD,oldSeed:DWORD,oldX:DWORD,oldY:DWORD,oldAngle:DWORD
|
||||
local total:DWORD,iterations:DWORD,expected:DWORD,rngSnapshot:DWORD,ticks:DWORD
|
||||
local previous:DWORD,reel:DWORD,timer:DWORD,first:DWORD,second:DWORD,third:DWORD
|
||||
mov eax,bankroll
|
||||
mov oldBank,eax
|
||||
mov eax,engineMode
|
||||
mov oldMode,eax
|
||||
mov eax,rngSeed3D
|
||||
mov oldSeed,eax
|
||||
mov eax,playerX
|
||||
mov oldX,eax
|
||||
mov eax,playerY
|
||||
mov oldY,eax
|
||||
mov eax,playerAngle
|
||||
mov oldAngle,eax
|
||||
mov bankroll,100000
|
||||
mov slotsTestStage3D,1
|
||||
mov engineMode,MODE_WALK
|
||||
mov interactTargetId,INTERACT_SLOTS_777
|
||||
call Trigger3DInteraction
|
||||
cmp engineMode,MODE_SLOTS
|
||||
jne slots_test_fail
|
||||
cmp bankroll,100000
|
||||
jne slots_test_fail
|
||||
cmp slotSpinState,SLOT_READY
|
||||
jne slots_test_fail
|
||||
call TableBusy3D
|
||||
test eax,eax
|
||||
jnz slots_test_fail
|
||||
call RenderNativeSlots3D
|
||||
invoke WriteActionSnapshot3D,OFFSET slotsTest0
|
||||
test eax,eax
|
||||
jz slots_test_fail
|
||||
; Invalid dimensions fail closed, with no charged stake or loaded remnants.
|
||||
mov slotSymbolsPack3D.frames,7
|
||||
call InitNativeSlots3D
|
||||
test eax,eax
|
||||
jnz slots_test_fail
|
||||
cmp slotSymbolsPack3D.pixels,0
|
||||
jne slots_test_fail
|
||||
cmp slotCabinetPack3D.pixels,0
|
||||
jne slots_test_fail
|
||||
call StartNativeSlots3D
|
||||
cmp bankroll,100000
|
||||
jne slots_test_fail
|
||||
mov BYTE PTR slotSymbolsPath3D,'!'
|
||||
call InitNativeSlots3D
|
||||
mov BYTE PTR slotSymbolsPath3D,'a'
|
||||
test eax,eax
|
||||
jnz slots_test_fail
|
||||
cmp slotCabinetPack3D.pixels,0
|
||||
jne slots_test_fail
|
||||
call InitNativeSlots3D
|
||||
test eax,eax
|
||||
jz slots_test_fail
|
||||
mov slotBet,0
|
||||
call StartNativeSlots3D
|
||||
cmp slotSpinState,SLOT_READY
|
||||
jne slots_test_fail
|
||||
mov slotBet,10001
|
||||
call StartNativeSlots3D
|
||||
cmp bankroll,100000
|
||||
jne slots_test_fail
|
||||
mov bankroll,49
|
||||
mov slotBet,50
|
||||
mov eax,rngSeed3D
|
||||
mov rngSnapshot,eax
|
||||
call StartNativeSlots3D
|
||||
cmp bankroll,49
|
||||
jne slots_test_fail
|
||||
mov eax,rngSnapshot
|
||||
cmp rngSeed3D,eax
|
||||
jne slots_test_fail
|
||||
cmp slotError3D,1
|
||||
jne slots_test_fail
|
||||
; Every possible 20^3 stop combination exercises the actual MASM evaluator.
|
||||
mov slotsTestStage3D,2
|
||||
mov total,0
|
||||
xor ebx,ebx
|
||||
slots_test_first:
|
||||
xor esi,esi
|
||||
slots_test_second:
|
||||
xor edi,edi
|
||||
slots_test_third:
|
||||
mov eax,slotStrip3D[ebx*4]
|
||||
mov first,eax
|
||||
mov eax,slotStrip3D[esi*4]
|
||||
mov second,eax
|
||||
mov eax,slotStrip3D[edi*4]
|
||||
mov third,eax
|
||||
invoke SlotMultiplier3D,first,second,third
|
||||
add total,eax
|
||||
mov expected,eax
|
||||
mov ecx,first
|
||||
cmp ecx,second
|
||||
jne slots_test_pair_other
|
||||
cmp ecx,third
|
||||
jne slots_test_pair
|
||||
mov eax,slotTriple3D[ecx*4]
|
||||
jmp slots_test_compare
|
||||
slots_test_pair_other:
|
||||
cmp ecx,third
|
||||
je slots_test_pair
|
||||
mov ecx,second
|
||||
cmp ecx,third
|
||||
jne slots_test_zero
|
||||
slots_test_pair:
|
||||
xor eax,eax
|
||||
cmp ecx,1
|
||||
sete al
|
||||
inc eax
|
||||
jmp slots_test_compare
|
||||
slots_test_zero:
|
||||
xor eax,eax
|
||||
slots_test_compare:
|
||||
cmp eax,expected
|
||||
jne slots_test_fail
|
||||
inc edi
|
||||
cmp edi,20
|
||||
jb slots_test_third
|
||||
inc esi
|
||||
cmp esi,20
|
||||
jb slots_test_second
|
||||
inc ebx
|
||||
cmp ebx,20
|
||||
jb slots_test_first
|
||||
cmp total,7202
|
||||
jne slots_test_fail
|
||||
invoke SlotMultiplier3D,8,8,8
|
||||
test eax,eax
|
||||
jnz slots_test_fail
|
||||
; Five hundred complete paid spins at four update rates, no double debit/pay.
|
||||
mov slotsTestStage3D,3
|
||||
mov iterations,500
|
||||
slots_test_round:
|
||||
mov slotSpinState,SLOT_READY
|
||||
mov slotBet,100
|
||||
mov slotPaytable3D,0
|
||||
mov bankroll,100000
|
||||
call StartNativeSlots3D
|
||||
cmp bankroll,99900
|
||||
jne slots_test_fail
|
||||
cmp slotSpinState,SLOT_SPIN
|
||||
jne slots_test_fail
|
||||
mov eax,rngSeed3D
|
||||
mov rngSnapshot,eax
|
||||
call StartNativeSlots3D
|
||||
cmp bankroll,99900
|
||||
jne slots_test_fail
|
||||
mov eax,rngSnapshot
|
||||
cmp rngSeed3D,eax
|
||||
jne slots_test_fail
|
||||
invoke SlotMultiplier3D,slotReel1,slotReel2,slotReel3
|
||||
imul eax,100
|
||||
add eax,99900
|
||||
mov expected,eax
|
||||
mov eax,iterations
|
||||
and eax,3
|
||||
mov eax,slotsTestRates[eax*4]
|
||||
mov deltaTime3D,eax
|
||||
mov ticks,0
|
||||
slots_test_round_tick:
|
||||
; Spinning ignores wager and start input, rather than queueing it for later.
|
||||
mov pressedKeys3D[57h],1
|
||||
mov pressedKeys3D[20h],1
|
||||
call HandleNativeSlots3D
|
||||
call ClearKeys3D
|
||||
cmp slotBet,100
|
||||
jne slots_test_fail
|
||||
mov eax,rngSnapshot
|
||||
cmp rngSeed3D,eax
|
||||
jne slots_test_fail
|
||||
inc ticks
|
||||
cmp ticks,200
|
||||
ja slots_test_fail
|
||||
cmp slotSpinState,SLOT_SPIN
|
||||
je slots_test_round_tick
|
||||
mov eax,expected
|
||||
cmp bankroll,eax
|
||||
jne slots_test_fail
|
||||
call SettleNativeSlots3D
|
||||
mov eax,expected
|
||||
cmp bankroll,eax
|
||||
jne slots_test_fail
|
||||
xor esi,esi
|
||||
slots_test_final_reel:
|
||||
invoke SlotReelPosition3D,esi
|
||||
shr eax,6
|
||||
cmp eax,slotTargets3D[esi*4]
|
||||
jne slots_test_fail
|
||||
inc esi
|
||||
cmp esi,3
|
||||
jb slots_test_final_reel
|
||||
dec iterations
|
||||
jnz slots_test_round
|
||||
; The same millisecond timestamp gives the same strictly nondecreasing path.
|
||||
mov slotsTestStage3D,4
|
||||
mov slotSpinState,SLOT_SPIN
|
||||
mov reel,0
|
||||
slots_test_monotonic_reel:
|
||||
mov timer,0
|
||||
mov previous,0
|
||||
slots_test_monotonic_tick:
|
||||
mov eax,timer
|
||||
mov slotSpinTimer,eax
|
||||
invoke SlotReelPosition3D,reel
|
||||
cmp eax,previous
|
||||
jb slots_test_fail
|
||||
mov previous,eax
|
||||
inc timer
|
||||
cmp timer,3000
|
||||
jbe slots_test_monotonic_tick
|
||||
inc reel
|
||||
cmp reel,3
|
||||
jb slots_test_monotonic_reel
|
||||
; Force known stops for visual timing snapshots; neither drawing nor a panel pays.
|
||||
mov slotsTestStage3D,5
|
||||
mov slotSpinState,SLOT_READY
|
||||
mov slotStops3D,0
|
||||
mov slotStops3D[4],6
|
||||
mov slotStops3D[8],12
|
||||
mov bankroll,100000
|
||||
call StartNativeSlots3D
|
||||
mov slotReel1,0
|
||||
mov slotReel2,0
|
||||
mov slotReel3,0
|
||||
xor esi,esi
|
||||
slots_test_force_sevens:
|
||||
mov slotTargets3D[esi*4],10
|
||||
mov eax,10
|
||||
sub eax,slotStartStops3D[esi*4]
|
||||
jns @F
|
||||
add eax,20
|
||||
@@:
|
||||
add eax,slotCycles3D[esi*4]
|
||||
shl eax,6
|
||||
mov slotTravel3D[esi*4],eax
|
||||
inc esi
|
||||
cmp esi,3
|
||||
jb slots_test_force_sevens
|
||||
xor esi,esi
|
||||
slots_test_snapshots:
|
||||
mov eax,slotsTestTimes[esi*4]
|
||||
mov slotSpinTimer,eax
|
||||
mov eax,rngSeed3D
|
||||
mov rngSnapshot,eax
|
||||
call RenderNativeSlots3D
|
||||
mov eax,rngSnapshot
|
||||
cmp rngSeed3D,eax
|
||||
jne slots_test_fail
|
||||
cmp bankroll,99900
|
||||
jne slots_test_fail
|
||||
mov eax,slotsTestTimes[esi*4]
|
||||
cmp slotSpinTimer,eax
|
||||
jne slots_test_fail
|
||||
invoke WriteActionSnapshot3D,slotsTestPaths[esi*4]
|
||||
test eax,eax
|
||||
jz slots_test_fail
|
||||
inc esi
|
||||
cmp esi,4
|
||||
jb slots_test_snapshots
|
||||
call SettleNativeSlots3D
|
||||
cmp bankroll,109900
|
||||
jne slots_test_fail
|
||||
call RenderNativeSlots3D
|
||||
invoke WriteActionSnapshot3D,OFFSET slotsTest5
|
||||
mov pressedKeys3D[50h],1
|
||||
mov deltaTime3D,16
|
||||
call HandleNativeSlots3D
|
||||
cmp slotPaytable3D,1
|
||||
jne slots_test_fail
|
||||
call RenderNativeSlots3D
|
||||
invoke WriteActionSnapshot3D,OFFSET slotsTest6
|
||||
call StartNativeSlots3D
|
||||
cmp bankroll,109900
|
||||
jne slots_test_fail
|
||||
call SlotEscape3D
|
||||
cmp slotPaytable3D,0
|
||||
jne slots_test_fail
|
||||
cmp engineMode,MODE_SLOTS
|
||||
jne slots_test_fail
|
||||
; Header clicks use the same safe queued-exit path as Escape.
|
||||
mov slotsTestStage3D,6
|
||||
call StartNativeSlots3D
|
||||
invoke SlotMultiplier3D,slotReel1,slotReel2,slotReel3
|
||||
imul eax,100
|
||||
add eax,109800
|
||||
mov expected,eax
|
||||
mov mouseClick3D,1
|
||||
mov mouseX3D,280
|
||||
mov mouseY3D,9
|
||||
call HandleNativeSlots3D
|
||||
cmp slotLeaveAfter3D,1
|
||||
jne slots_test_fail
|
||||
cmp paused3D,0
|
||||
jne slots_test_fail
|
||||
cmp engineMode,MODE_SLOTS
|
||||
jne slots_test_fail
|
||||
call RenderNativeSlots3D
|
||||
invoke WriteActionSnapshot3D,OFFSET slotsTest7
|
||||
mov deltaTime3D,250
|
||||
mov ticks,0
|
||||
slots_test_exit_tick:
|
||||
call HandleNativeSlots3D
|
||||
inc ticks
|
||||
cmp ticks,13
|
||||
ja slots_test_fail
|
||||
cmp engineMode,MODE_SLOTS
|
||||
je slots_test_exit_tick
|
||||
cmp engineMode,MODE_WALK
|
||||
jne slots_test_fail
|
||||
mov eax,expected
|
||||
cmp bankroll,eax
|
||||
jne slots_test_fail
|
||||
mov eax,oldX
|
||||
cmp playerX,eax
|
||||
jne slots_test_fail
|
||||
mov eax,oldY
|
||||
cmp playerY,eax
|
||||
jne slots_test_fail
|
||||
mov eax,oldAngle
|
||||
cmp playerAngle,eax
|
||||
jne slots_test_fail
|
||||
; Mouse and key edge controls have identical bounded wager selections.
|
||||
mov slotsTestStage3D,7
|
||||
mov engineMode,MODE_SLOTS
|
||||
call InitNativeSlots3D
|
||||
test eax,eax
|
||||
jz slots_test_fail
|
||||
mov mouseX3D,44
|
||||
mov mouseY3D,226
|
||||
mov mouseClick3D,1
|
||||
call HandleNativeSlots3D
|
||||
cmp slotBet,100
|
||||
jne slots_test_fail
|
||||
call HandleNativeSlots3D
|
||||
cmp slotBet,100
|
||||
jne slots_test_fail
|
||||
mov pressedKeys3D[53h],1
|
||||
call HandleNativeSlots3D
|
||||
cmp slotBet,50
|
||||
jne slots_test_fail
|
||||
call HandleNativeSlots3D
|
||||
cmp slotBet,50
|
||||
jne slots_test_fail
|
||||
mov slotBetIndex3D,0
|
||||
mov slotBet,10
|
||||
mov pressedKeys3D[28h],1
|
||||
call HandleNativeSlots3D
|
||||
cmp slotBet,10
|
||||
jne slots_test_fail
|
||||
mov slotBetIndex3D,6
|
||||
mov slotBet,10000
|
||||
mov pressedKeys3D[26h],1
|
||||
call HandleNativeSlots3D
|
||||
cmp slotBet,10000
|
||||
jne slots_test_fail
|
||||
mov bankroll,100000
|
||||
call StartNativeSlots3D
|
||||
invoke SlotMultiplier3D,slotReel1,slotReel2,slotReel3
|
||||
imul eax,10000
|
||||
add eax,90000
|
||||
mov expected,eax
|
||||
mov slotSpinTimer,2999
|
||||
mov deltaTime3D,16
|
||||
mov mouseX3D,280
|
||||
mov mouseY3D,9
|
||||
mov mouseClick3D,1
|
||||
call HandleNativeSlots3D
|
||||
cmp engineMode,MODE_WALK
|
||||
jne slots_test_fail
|
||||
mov eax,expected
|
||||
cmp bankroll,eax
|
||||
jne slots_test_fail
|
||||
mov engineMode,MODE_SLOTS
|
||||
call CardTableEscape3D
|
||||
cmp eax,1
|
||||
jne slots_test_fail
|
||||
cmp engineMode,MODE_WALK
|
||||
jne slots_test_fail
|
||||
; Bank cap and idempotent settlement remain safe at the maximum wager.
|
||||
mov bankroll,999999999
|
||||
mov slotStake3D,10000
|
||||
mov slotReel1,7
|
||||
mov slotReel2,7
|
||||
mov slotReel3,7
|
||||
mov slotSpinState,SLOT_SPIN
|
||||
call SettleNativeSlots3D
|
||||
cmp bankroll,1000000000
|
||||
jne slots_test_fail
|
||||
call SettleNativeSlots3D
|
||||
cmp bankroll,1000000000
|
||||
jne slots_test_fail
|
||||
mov eax,oldBank
|
||||
mov bankroll,eax
|
||||
mov eax,oldSeed
|
||||
mov rngSeed3D,eax
|
||||
mov eax,oldMode
|
||||
mov engineMode,eax
|
||||
call ClearKeys3D
|
||||
call FreeNativeSlots3D
|
||||
xor eax,eax
|
||||
ret
|
||||
slots_test_fail:
|
||||
mov eax,slotsTestStage3D
|
||||
add eax,440
|
||||
ret
|
||||
RunSlotsTest3D ENDP
|
||||
|
|
@ -6,10 +6,32 @@ include F:\MASM32\masm32\include\kernel32.inc
|
|||
InitPaths3D PROTO
|
||||
LoadAnimPack3D PROTO :DWORD,:DWORD
|
||||
FreeAnimPack3D PROTO :DWORD
|
||||
InitNativeSlots3D PROTO
|
||||
FreeNativeSlots3D PROTO
|
||||
LoadNativeWheelArt3D PROTO
|
||||
FreeNativeWheelArt3D PROTO
|
||||
LoadNativeCoinArt3D PROTO
|
||||
FreeNativeCoinArt3D PROTO
|
||||
.data
|
||||
streetPack dd 6 dup(0)
|
||||
streetPath db "assets\animations\hall\street-life-v4.bin",0
|
||||
missingPath db "assets\animations\hall\__missing_street_probe__.bin",0
|
||||
cardFurniturePath db "assets\animations\hall\card-table-v5.bin",0
|
||||
wheelFurniturePath db "assets\animations\hall\roulette-table-v5.bin",0
|
||||
backFurniturePath db "assets\animations\hall\backroom-table-v5.bin",0
|
||||
skillFurniturePath db "assets\animations\hall\skill-cabinet-v5.bin",0
|
||||
chairFurniturePath db "assets\animations\hall\lounge-chair-v5.bin",0
|
||||
lampFurniturePath db "assets\animations\hall\lamp-table-v5.bin",0
|
||||
ropeFurniturePath db "assets\animations\hall\velvet-rope-v5.bin",0
|
||||
slotFurniturePath db "assets\animations\hall\slot-cabinets-v5.bin",0
|
||||
furniturePaths dd OFFSET cardFurniturePath,320,208,1
|
||||
dd OFFSET wheelFurniturePath,288,268,1
|
||||
dd OFFSET backFurniturePath,304,236,1
|
||||
dd OFFSET skillFurniturePath,224,368,1
|
||||
dd OFFSET chairFurniturePath,240,256,1
|
||||
dd OFFSET lampFurniturePath,192,224,1
|
||||
dd OFFSET ropeFurniturePath,288,192,1
|
||||
dd OFFSET slotFurniturePath,224,256,3
|
||||
.code
|
||||
RunStreetAssetProbe PROC
|
||||
call InitPaths3D
|
||||
|
|
@ -25,6 +47,40 @@ RunStreetAssetProbe PROC
|
|||
cmp streetPack[20],0
|
||||
je probe_failed
|
||||
invoke FreeAnimPack3D,OFFSET streetPack
|
||||
; The newly playable cabinet must resolve its packs from these launch paths too.
|
||||
call InitNativeSlots3D
|
||||
cmp eax,1
|
||||
jne probe_failed
|
||||
call FreeNativeSlots3D
|
||||
call LoadNativeWheelArt3D
|
||||
cmp eax,1
|
||||
jne probe_failed
|
||||
call FreeNativeWheelArt3D
|
||||
call LoadNativeCoinArt3D
|
||||
cmp eax,1
|
||||
jne probe_failed
|
||||
call FreeNativeCoinArt3D
|
||||
mov esi,OFFSET furniturePaths
|
||||
mov edi,8
|
||||
probe_furniture:
|
||||
invoke LoadAnimPack3D,OFFSET streetPack,[esi]
|
||||
cmp eax,1
|
||||
jne probe_failed
|
||||
mov eax,[esi+4]
|
||||
cmp streetPack[4],eax
|
||||
jne probe_failed
|
||||
mov eax,[esi+8]
|
||||
cmp streetPack[8],eax
|
||||
jne probe_failed
|
||||
mov eax,[esi+12]
|
||||
cmp streetPack[12],eax
|
||||
jne probe_failed
|
||||
cmp streetPack[20],0
|
||||
je probe_failed
|
||||
invoke FreeAnimPack3D,OFFSET streetPack
|
||||
add esi,16
|
||||
dec edi
|
||||
jnz probe_furniture
|
||||
; Rejecting a missing asset must not leave a plausible loaded header behind.
|
||||
invoke LoadAnimPack3D,OFFSET streetPack,OFFSET missingPath
|
||||
test eax,eax
|
||||
|
|
|
|||