33#include "text/msg_ids.h"
45#define REEL_SPARKS ((struct EffectStep *)Ram_MapCellBuffer)
49#define REEL_HEAP_SLOT 45
53#define REEL_CANVAS_SIZE (256 * 128)
54#define REEL_CANVAS_TILES (BG_CHAR_BLOCK(0) + 0x3500)
92 col = ((r >> 16) & redMask) | ((g >> 16) & greenMask);
93 col |= (b >> 16) & blueMask;
144 for (i = 0; i != 16; i++) {
145 s32 b = (*col >> 10) & 0x1f;
146 s32 g = (*col >> 5) & 0x1f;
159 *col++ =
RGB(r, g, b);
162 for (i = 0; i != 239; i++) {
163 s32 b = (*col >> 10) & 0x1f;
164 s32 g = (*col >> 5) & 0x1f;
177 *col++ =
RGB(r, g, b);
190 for (i = 0; i != 64; i++, col++) {
192 s32 g = (*col >> 5) & 0x1f;
193 s32 b = (*col >> 10) & 0x1f;
194 s32 targetRed = dst[i] & 0x1f;
195 s32 targetGreen = (dst[i] >> 5) & 0x1f;
196 s32 targetBlue = (dst[i] >> 10) & 0x1f;
200 else if (r > targetRed)
204 else if (g > targetGreen)
208 else if (b > targetBlue)
210 dst[i] =
RGB(r, g, b);
241 step = (
ABS(x1 - x0) << 8) /
ABS(y1 - y0);
243 for (i = y0; i != y1; i++) {
244 offset = (((((
u32)i >> 3) << 5) + ((
u32)x >> 3)) << 3) + (i & 7);
245 offset = (offset << 3) + (x & 7);
246 if (canvas[offset] < color)
247 canvas[offset] = color;
269 step = (
ABS(y1 - y0) << 8) /
ABS(x1 - x0);
271 for (i = x0; i != x1; i++) {
272 offset = (((((
u32)y >> 3) << 5) + ((
u32)i >> 3)) << 3) + (y & 7);
273 offset = (offset << 3) + (i & 7);
274 if (canvas[offset] < color)
275 canvas[offset] = color;
421 if (work->
bet <= 3 && tickets > work->
bet) {
442 for (k = 0; k != work->
bet; k++)
451 for (k = 0; k != 5 && work->
reels[k].
held != 0; k++)
458 if (work->
spins == 4) {
462 for (i = 0; i != 5; i++) {
466 }
else if (work->
cursor <= 4) {
469 }
else if (allHeld == 0) {
473 for (i = 0; i != 5; i++)
501 }
else if (work->
phase == 1) {
507 if (work->
phase != 3) {
517 if (work->
phase != 4) {
525 if (work->
phase != 5) {
560 if (work->
timer == 60) {
578 if (work->
phase == 0) {
593 if (work->
timer == 45)
596 if (work->
timer == 4) {
601 if (work->
timer == 16)
603 if (work->
timer > 56) {
606 for (i = 0; i != 5; i++) {
616 for (i = 0; i != 5; i++) {
622 for (i = 0; i != 5; i++) {
630 if (stoppedReels == 5) {
634 for (col = 0; col != 7; col++) {
641 if (col > 3 - work->
bet && col < work->bet + 3) {
642 for (i = 0; i != 5; i++) {
660 else if (found != sym)
685#if REEL_HINT_BEFORE_LAST_SPIN
686 if (work->
spins <= 3)
699 message = MsgSlotsChooseHeld;
704 if (work->
spins == 4) {
713 if (work->
bet > left)
717 for (i = 0; i != 5; i++) {
726 message = MsgSlotsBet;
734 for (i = 0; i != 5; i++) {
737 if (reel->
held == 0) {
740 else if ((reel->
position & 15) != 8)
753 x = work->
cursor * 36 + 36;
756 if ((work->
timer & 15) <= 7)
763 ((x - 12) << 16) | objMode | (y + 8) | 0x80006000;
764 work->
obj[sprite].
attr2 = (v << 4) + 0x2b0;
767 ((x + 12) << 16) | objMode | (y + 8) | 0x90006000;
768 work->
obj[sprite].
attr2 = (v << 4) + 0x2b0;
770 work->
obj[sprite].
attr01 = (x << 16) | objMode | y | 0x80002000;
779#if (LANGUAGE == LANGUAGE_SPANISH)
782 (((*(
s16 *)((
u8 *)&p->
x + 2) + 0x1f0) & 0x1ff) << 16) | objMode |
783 ((*(
s16 *)((
u8 *)&p->
y + 2) + 0x108) & 255) | 0xb0000000;
786 work->
obj[sprite].
attr01 = (*(
s16 *)((
u8 *)&p->
x + 2) << 16) | objMode |
787 ((*(
s16 *)((
u8 *)&p->
y + 2) + 256) & 255) |
793 if (work->
timer % 256 == i * 4 + 200) {
797 if (p->
y > 0x400000) {
807 for (k = 0; k != 14; k++) {
817 for (i = 0; i != 5; i++) {
819 work->
obj[sprite].
attr01 = objMode | ((i * 36 + 32) << 16) | 0x8000207c;
822 work->
obj[sprite].
attr01 = objMode | ((i * 36 + 32) << 16) | 0x8000207c;
828 for (i = 0; i != 5; i++) {
829 work->
obj[sprite].
attr01 = objMode | ((i * 16 + 32) << 16) | 0x80006003;
830 if (i == work->
spins)
831 work->
obj[sprite].
attr2 = (i * 32 + 0x210) | 0x400;
833 work->
obj[sprite].
attr2 = (i * 32 + 0x220) | 0x400;
837 for (col = 0; col != 7; col++) {
838 work->
obj[sprite].
attr01 = (((0x204 - ((col & 1) << 3)) & 0x1ff) << 16) |
839 objMode | (col * 16 + 5) | 0x80002000;
840 if (col > 3 - work->
bet && col < work->bet + 3)
847 for (i = 0; i != 5; i++) {
850 for (col = 0; col != 7; col++) {
852 ((i * 32 + 40) << 16) | 0x80006000;
861 if (work->
timer <= 47)
863 else if (work->
timer <= 55)
864 lever = ((
Trig_Sin((work->
timer << 12) - 0x30000) << 2) >> 16) + 40;
866 work->
obj[sprite].
attr01 = lever | objMode | 0x80d06000;
870 for (k = 0; k != 8; k++) {
871 work->
obj[sprite].
attr01 = objMode | (k * 16 + 12) | 0x80ce6000;
885 while (sprite != 128) {
914 for (i = 0; i != 0x800; i++)
931 for (i = 0; i != 160; i++)
932 state->scanlineOffsets[i] = 0;
934 for (i = 0; i != 40; i++) {
948 message = MsgSlotsBet;
991 for (k = 0; k != 20; k++) {
992 for (i = 0; i != 32; i++, j += 2) {
993 if (i >= 5 && i <= 24 && k > 2 && k <= 13) {
1011 for (k = 0; k != 20; k++) {
1012 for (i = 0; i != 30; i++) {
1013 if (!(i >= 5 && i <= 24 && k > 2 && k <= 13)) {
1014 Dma_Set(tiles + (k * 30 + i) * 32,
1023 for (k = 0; k != 20; k++) {
1024 for (i = 0; i != 32; i++, j += 2) {
1025 if (k < 2 || k > 16)
1059 u16 *shade = (
u16 *)(work->sheet + 0x200);
1088 for (i = 0; i != 5; i++) {
1094 for (k = 0; k != 21; k++)
1097 for (i = 0; i != 5; i++) {
1100 for (j = 0; j != 8; j++) {
1102 for (k = 0; k != j; k++) {
1103 if (picks[j] == picks[k]) {
1109 for (k = 0; k != 8; k++) {
1114 reel->
symbols[picks[k]] = rank;
1136 state->window = window;
1143 state->window = window;
1144 message = MsgSlotsChangeBet;
1148 work->transferPending = 0;
1162 else if (phase <= 31)
1164 else if (phase <= 47)
1166 else if (phase <= 63)
1170 if (
state->timer <= 15)
1177 for (j = 0; j != 256; j++) {
1192 for (j = 0; j != 1024; j++) {
1200 if (
x >= 0 &&
x <= 0xffffff) {
1203 if (
y <= 0x7fffff) {
1211 px - size, py - size, size * 2, size * 2);
1223 for (j = 0; j != 7; j++)
1227 if (state->
bet > 1) {
1231 if (state->
bet > 2) {
1235 if (state->
bet > 3) {
1239 }
else if ((frame & 7) <= 3) {
1240 for (j = 0; j != 7; j++)
1243 for (j = 0; j != 3; j++) {
1263 work->transferPending = 1;
1267 for (j = 0; j != 17; j++) {
1286#define PACK_WINDOW_MASK 0x3ff
1287#define PACK_MATCH_MAX 272
1288#define PACK_DISTANCE_MAX 63
1289#define PACK_LOOKAHEAD 672
1297 for (index = 0; index < 0x400; index++) {
1302 for (index = 0xFF; index >= 0; index--) {
1337 if (current < limit) {
1339 u32 removal = base + 0x124;
1351 value = input[readOffset];
1352 nextOffset = readOffset + 1;
1363 }
while (current < limit);
1367 if (current < limit) {
1373 u32 slot = (base + current) & mask;
1380 }
while (current < limit);
1390 for (index = 0; index != work->
outCnt; index++) {
1409 while (node !=
NULL) {
1431 while (node !=
NULL) {
1493 if (reach[0] >= reach[1]) {
The sound driver's command masks, cue controls and the routines and globals it shares with the engine...
The battle effect argument and the rectangle-drawing routines effects call.
BattleEffectDrawRectangle DrawRectangle
BattleEffectWork, the running battle effect's work, and its animation objects.
The task scheduler: tasks, their order and the scheduler's state.
void ReelGame_DrawCanvasLine(s32 x0, s32 y0, s32 x1, s32 y1, s32 color)
Draws a line from (x0, y0) to (x1, y1) on the 256 x 128 8bpp canvas (32 tiles across),...
#define REEL_HEAP_SLOT
The slot machine's own work block (struct ReelWork), beside the battle effect blocks it borrows.
#define REEL_CANVAS_TILES
s32 ReelGame_Start(void)
Plays the slot machine: blanks the screen, seeds the random numbers with the play time and runs the g...
static __inline__ void LzPack_FindWindowMatch(s32 start)
Finds the longest earlier match (up to PACK_MATCH_MAX bytes, at most PACK_DISTANCE_MAX back) for the ...
void ReelGame_TransferCanvas(void)
A scheduler callback: on a frame whose canvas is ready (transferPending), sends the canvas to its til...
void Palette_StepTowardResource(s32 resource)
Moves the first 64 BG colours one step toward the palette of resource; the backdrop colour is not wri...
#define PACK_DISTANCE_MAX
s32 Graphics_ScaleRgb555(u16 *src, u16 *dst, s32 scale, s32 count)
Writes count RGB555 colours from src to dst scaled by scale (16.16, 0x10000 keeps them).
void LzPack_CopyBufferedBytes(u8 *destination)
Appends the finished group (a flag byte and up to eight items) to the output.
#define REEL_SPARKS
The sparks of the jackpot, kept in the map cell buffer.
void LzPack_ResetSlotBuckets(void)
The LZ packer below: empties its 256 hash chains (one per byte value) and numbers its 1024 window nod...
ReelGameState
The slot machine's states (ReelWork.state).
@ REEL_NO_WIN
no payline won: A to choose holds
@ REEL_WON
a payline won: a pause
@ REEL_SHOWING_WIN
the win is shown until A
@ REEL_BETTING
Up and Down change the bet, A spins, B leaves.
@ REEL_CHOOSING_HOLDS
choose reels to hold, or pull the lever
@ REEL_OUT_OF_SPINS
the fourth spin lost: a pause, then the end
@ REEL_SPINNING
the reels spin until R or time stops each
UNUSED s32 LzPack_PackStream(const u8 *input, u8 *dst, s32 size)
Packs size bytes of input into dst with a small LZ scheme and returns the packed size.
void LzPack_RemoveSlotNode(s32 slot)
Removes window position slot from its chain.
#define REEL_CANVAS_SIZE
The paylines' canvas: 256 x 128 pixels of 8-bit colour, shown on BG2 from its tile 212,...
void LzPack_InsertSlotNode(s32 index)
Adds window position index to the chain of the byte it holds.
void ReelGame_Run(void)
The slot machine: loads its backgrounds, sprites and palettes, fills each of the five reels with 21 r...
void ReelGame_InitTitle(void)
Sets up the bouncing title letters of a win, the brightness wave of the screen's lines and the bettin...
void Palette_DarkenSceneStep(void)
Darkens the screen one step: lowers each channel of the 16 colours of BG palette 10 and of OBJ colour...
void LzPack_ConsumeSlotBytes(s32 start, s32 count, const u8 *input)
Reads count more input bytes into the window from position start, dropping the bytes they replace fro...
void ReelGame_RunFrame(void)
The slot machine's frame callback: reads the keys, runs the game's state (betting,...
u16 gFlash_Handler3
Credits scroll position in pixels, in the low half of a flash work cell.
The engine calls the debug menus import, and their palette swatch tiles.
DMA channel registers, and the DMA and CPU fills.
static __inline__ void Dma_Set(const volatile void *source, volatile void *destination, u32 control, volatile u32 *channel)
Starts a DMA transfer: stores the source, destination and control words into channel's registers with...
EffectStep and EffectPosition, the positions effects move through.
s32 BattleEffect_LoadWorkFar(s32 slot, s32 width_shift, s32 height_shift, s32 flags, u32 mode)
Far call to BattleFx_BuildBlitter.
s32 PartyInventory_CountItemFar(s32 item_id)
s32 PartyInventory_RemoveFar(s32 item_id)
void AudioCommand_PlayFar(s32 id)
struct UiWindow * UiWindow_CreateFar(s32 x, s32 y, s32 width, s32 height, s32 attrs)
void UiText_DrawNumberInWindowFar(s32 arg0, s32 arg1, struct UiWindow *arg2, s32 arg3, s32 arg4)
void UiText_DrawCharacterAtOffsetFar(s32 character, const struct UiWindow *position, u32 offsetX, u32 offsetY)
void UiWork_FinalizeFar(struct UiWindow *work, s32 release)
void UiWork_InitializeWithResourceCountersFar(void)
16.16 fixed-point constants, sine and cosine, and the library division.
void WaitFrames(s32 frames)
The game's frame loop: runs frames frames and returns.
The frame loop's globals: lag counts, the CPU load display and the VBlank flags.
u8 gOamCopyEnabled
The VBlank handler copies the OAM list only while it is set; scenes clear it to keep their own sprite...
u8 gDebugPaused
The debug pause is on.
GameState, the game's state: play time, coins, the scene and the leader's position,...
struct GameState gGameState
struct EffectStep gMapCellBuffer[]
Map cells; battle effects reuse this as a particle array.
The screen blend's globals and the graphics routines.
void * Runtime_AllocateBlock(s32 kind, s32 size)
As Runtime_AllocateHeapBlock, but tries EWRAM first, for blocks that need room more than speed: the b...
void * Runtime_AllocateHeapBlock(s32 kind, s32 size)
Returns heap slot kind's block, first allocating size bytes for it (rounded up to words),...
The heap's work slots and HeapState.
@ HEAP_SLOT_BATTLE_EFFECT
@ HEAP_SLOT_BLITTER_ALTERNATE
@ HEAP_SLOT_BATTLE_CANVAS
The hardware's I/O registers and their bits, as pret names them.
#define WINOUT_WINOBJ_BG2
#define BGCNT_CHAR_BASE(block)
#define BGCNT_PRIORITY(n)
#define BG_SCREEN_BLOCK(n)
#define DMA_HBLANK_HALFWORD_PER_LINE
#define RGB(r, g, b)
A 15-bit colour from its red, green and blue levels (0 to 31 each), as the palette stores it: blue in...
#define BLDCNT_EFFECT_DARKEN
towards black by REG_BLDY
#define DMA_START_TIMING_DRQ_REPEAT
A DMA control's start timing (bits 12 and 13), cartridge request (bit 11) and repeat (bit 9): the bit...
#define OBJ_VRAM0
Sprite tile memory, as pret names it: the 32 KB from 0x06010000.
#define OBJ_PLTT_COLOR(palette, color)
#define BLDCNT_EFFECT_BLEND
weighted by REG_BLDALPHA
#define WINOUT_WINOBJ_BG1
#define BLEND_ALPHA(top, bottom)
A REG_BLDALPHA value: top and bottom are the two targets' weights, out of 16.
#define BGCNT_SCREEN_BASE(block)
#define WINOUT_WINOBJ_CLR
#define WIN_RANGE(start, end)
A REG_WINxH or REG_WINxV value: the window covers start up to, but not including, end.
#define WINOUT_WINOBJ_BG0
#define BG_PLTT_COLOR(palette, color)
Item numbers, named from the English release.
The IWRAM call layer: the routines the game keeps resident in IWRAM, each at its fixed address,...
static s32 Iwram_FillWords(void *destination, s32 size, u32 value)
static s32 Iwram_ClearWords(void *destination, s32 size)
The keypad state the VBlank interrupt keeps.
volatile u32 gKeysHeld
Keys down now.
The LZ packer's work: hash chains over a 1024-byte window, one chain per byte value,...
Small statement macros both games use for positions, velocities and bounds.
#define ABS(v)
The magnitude of v. v is read twice.
u32 Random16(void)
Advances the game's random number generator (the C library's classic linear congruential one),...
The heaps: allocating and freeing blocks.
void Runtime_ReleaseHeapBlock(s32 slot)
The reel game's title lettering.
OamShadow, a sprite entry a routine builds by hand and DMA copies to OAM.
The work pointers in the gWorkSlot table, by name.
#define Ram_MapCellBuffer
The reel game's tables, the same in both games.
const u8 gReelGame_FrameSpriteX[]
The positions of the frame's sprites.
const u8 gReelGame_TitleLetterTiles[REEL_TITLE_LETTERS]
The tile of each title letter.
const u8 gReelGame_SymbolPrizes[]
The prize of each reel symbol.
const u8 gReelGame_TitleLetterWidths[REEL_TITLE_LETTERS]
The advance of each title letter.
const u8 gReelGame_FrameSpriteY[]
const u16 gReelGame_SparkCellOffsets[]
Where each spark cell (a square 2 to 20 pixels on a side) starts.
Resource numbers, named where their contents are known.
char ResourceId_LimePalette
char ResourceId_VenusDjinnSheet
char ResourceId_SlotsIcons
char ResourceId_EffectFarCalls
char ResourceId_ParticleSpritesD
char ResourceId_SlotsJackpot
char ResourceId_JupiterDjinnSheet
char ResourceId_SlotsFramePicture
char ResourceId_EmberStreakSheet
char ResourceId_MercuryDjinnSheet
s32 Resource_DecodeType01(const void *source, void *destination)
Decodes a type-01 resource and returns its unpacked byte count.
void ColorBuffer_BackupAndHalveNonzero(u8 *buffer, u8 *backup, u32 bytes)
Halves every pixel, skipping all-zero groups.
void ColorBuffer_BackupAndScaleNonzeroThreeQuarters(u8 *buffer, u8 *backup, u32 bytes)
Scales every pixel to three quarters, skipping all-zero groups.
s32 Scheduler_AddOrUpdateCallback(SchedulerCallback callback, s32 order)
Schedules callback with order, or gives a task already running it the new order, and re-sorts the tab...
void Scheduler_ResetTaskTable(void)
Empties the task table: every slot gets no routine, order 0xffff (sorted last) and no flags.
s32 Scheduler_RemoveCallback(SchedulerCallback callback)
Unschedules the task running callback: clears its routine and gives it order 0x7fff,...
Song and sound effect ids, indices into gSound_SongTable.
#define SE_MENU_CURSOR_MOVE
The running battle effect's work: its canvas image, 64 particles, the display registers it stages and...
s32 frame
frame counter some effects keep, from 0
s32 framesSinceTransfer
1 on a canvas copy's frame, then counts up
s32 transferPending
1 once the effect has drawn a frame (EFFECT_PRESENT_FRAME); the canvas transfer callback copies the c...
s32 transferMode
How the canvas transfer callbacks treat the canvas after each copy (enum CanvasTransferMode in effect...
s32 transferValue
The transfer mode's argument: the fill value, the share kept (50 or 75 percent) or the darken or brig...
struct EffectStep particles[64]
free while variant is -1
A moving point of an effect: its position, its velocity and a value each effect uses its own way (a s...
s32 velocityX
16.16 fixed-point pixels per frame
s32 variant
each effect's own: a size, a countdown, -1 for idle
s32 x
16.16 fixed-point pixels
s32 y
16.16 fixed-point pixels
s32 velocityY
16.16 fixed-point pixels per frame
u32 playTime
frames, copied from gPlayTimeFrames when saving
A position of the LZ packer's window in the chain of the byte value it holds.
struct LzPackNode * prev
Previous node, or the bucket field at the head.
struct LzPackNode * next
Next node with the same value.
The LZ packer's work: a node per window position, a chain head per byte value, the byte at each posit...
struct LzPackNode * bucket[0x100]
struct LzPackNode nodes[0x400]
OAM buffer: sprite entries a routine builds by hand and DMA copies to OAM.
volatile u32 attr2
attr2 | affine value << 16
volatile u32 attr01
attr0 | attr1 << 16
gGameState seen from +12, the base the bytes load: wonPrizes is gGameState.wonPrizes (through the fie...
The slot machine's work in heap slot 45: its reels, state, bet and spins, keys, timer,...
struct UiWindow * subWindow
struct OamShadow obj[128]
One of the slot machine's five reels: how far it has turned, its 21 symbols, whether it is held,...
s32 position
pixels, 16 a symbol
A window: a framed rectangle of the tilemap with its sprite outputs, its opening or closing animation...
u16 frame
The zoom's step: counts down from 7 to 0 while opening, and up from 0 to duration while closing.
u16 state
0 while a message channel is typing into the window; 1 once its text has ended or closed the window,...
void * Resource_GetTableEntry(s32 index)
Returns the ROM address of resource index from the resource directory.
void RuntimeDispatch_NoOpHook(s32 unused)
An exported stub that does nothing with its argument.
The system's routines and globals: interrupts, BIOS sound bias, random numbers and sleep.
Values that differ by patch level or language, chosen once for their code.
#define REEL_HELP_WINDOW_WIDTH
#define REEL_JACKPOT_COPY
#define REEL_HELP_WINDOW_X
#define REEL_RELEASE_WIDTH
#define REEL_JACKPOT_TILES
#define REEL_ALL_HELD_WIDTH
#define REEL_TITLE_LETTERS
The integer types, TRUE, UNUSED and the fixed-address macros.