49 camera->
pitch = 152 << 8;
82 s16 right = rightValue;
89 product *= multiplier;
91 roundedProduct = product;
93 roundedProduct = product + 255;
95 return (
s16)(roundedProduct >> 8);
102 return (numerator * 256) / denominator;
104 return (numerator << 8) / denominator;
122#include "text/msg_ids.h"
129#if (LANGUAGE == LANGUAGE_GERMAN) || (LANGUAGE == LANGUAGE_SPANISH) || \
130 (LANGUAGE == LANGUAGE_FRENCH)
131#define DICE_COIN_X 17
132#define DICE_COIN_W 13
134#elif (LANGUAGE != LANGUAGE_JAPANESE)
135#define DICE_COIN_X 18
136#define DICE_COIN_W 12
139#define DICE_COIN_X 18
140#define DICE_COIN_W 11
144#if (LANGUAGE == LANGUAGE_SPANISH)
145#define DICE_LABEL_X 56
146#elif (LANGUAGE == LANGUAGE_FRENCH)
147#define DICE_LABEL_X 53
149#define DICE_LABEL_X 48
152#if (LANGUAGE == LANGUAGE_GERMAN) || (LANGUAGE == LANGUAGE_SPANISH)
153#define DICE_HELP_X 20
154#define DICE_HELP_W 10
155#elif (LANGUAGE == LANGUAGE_FRENCH)
156#define DICE_HELP_X 21
158#elif (LANGUAGE != LANGUAGE_JAPANESE)
159#define DICE_HELP_X 22
162#define DICE_HELP_X 23
166#if (LANGUAGE != LANGUAGE_JAPANESE)
168#define DICE_WIN_NUM_X 48
169#define DICE_WIN_LABEL_X DICE_LABEL_X
170#define DICE_KIND_X 0x278
173#define DICE_WIN_NUM_X 40
174#define DICE_WIN_LABEL_X 40
175#define DICE_KIND_X 0x280
193#define DICE_FACE_COUNT 6
194#define DICE_RESULT_COUNT 4
195#define DICE_BET_PER_LEVEL 10
226 red = pixel & redMask;
227 green = pixel & greenMask;
228 blue = blueMask & pixel;
232 pixel = ((red >> 16) & redMask) | ((green >> 16) & greenMask);
233 pixel |= (blue >> 16) & blueMask;
234 *destination = pixel;
238 }
while (remaining != 0);
266 volatile u16 affineA;
267 volatile u16 affineB;
268 volatile u16 affineC;
269 volatile u16 affineD;
338 for (tileY = 0; tileY != 20; tileY++) {
339 for (tileX = 0; tileX != 32; tileX++) {
351 resourceAddress += 0x1c0;
363 Dma_Set((
void *)resourceAddress, spritePalette,
367 resourceAddress += 0x200;
410 for (index = 0; index !=
DICE_COUNT; index++) {
418 spinRate[index] = 300;
420 numbers[0] = numbers[1] = numbers[2] = numbers[3] = 0;
421 flashTimer[0] = flashTimer[1] = 0;
425 }
while (luckyNumbers[0] == luckyNumbers[1]);
461 sprites->
obj[spriteCount].
attr01 = 0xc0006000;
462 sprites->
obj[spriteCount].
attr2 = 0x358;
464 sprites->
obj[spriteCount].
attr01 = 0x40102020;
465 sprites->
obj[spriteCount].
attr2 = 0x398;
467 sprites->
obj[spriteCount].
attr01 = 0x40102030;
468 sprites->
obj[spriteCount].
attr2 = 0x3a0;
470 sprites->
obj[spriteCount].
attr01 = 0x40042020;
471 sprites->
obj[spriteCount].
attr2 = 0x3a8;
473 sprites->
obj[spriteCount].
attr01 = 0x40042030;
474 sprites->
obj[spriteCount].
attr2 = 0x3a8;
476 for (index = 0; index !=
DICE_COUNT; index++) {
477 sprites->
obj[spriteCount].
attr01 = (32 + index * 16) | 0x40202000;
478 sprites->
obj[spriteCount].
attr2 = luckyNumbers[index] * 8 + 0x3b0;
486 if (resultTimer == index * 5) {
489 if (resultTimer >= index * 5) {
491 0x80002040 | ((56 + index * 32) << 16);
492 sprites->
obj[spriteCount].
attr2 = numbers[index] * 32 + 152;
496 if (resultTimer > 19 && resultKind >= 0) {
505 (((labelX & 0x1ff) << 16) | labelY) | 0x80002000;
516 if (resultTimer == 20 && winnings > 0) {
520 }
else if (winnings <= 99) {
522 }
else if (winnings <= 999) {
524 }
else if (winnings <= 9999) {
540 if (payoutTimer > 0) {
564 if (payoutTimer == 0) {
570 if (payoutTimer == 15) {
629 for (index = 0; index !=
DICE_COUNT; index++) {
630 rollingDie = &diceWork->
particles[index];
634 rollingDie->
z = -0xb40000;
635 rollingDie->
y = 0x600000;
639 (((
Random16() & 63) + 140) << 12) + rollingDie->
y / 6);
641 spinRate[index] = 300;
647 if (resetDice == 1) {
657 }
while (luckyNumbers[0] == luckyNumbers[1]);
662 for (index = 0; index !=
DICE_COUNT; index++) {
663 drawOrder[index] = index;
665 for (index = 1; index <
DICE_COUNT; index++) {
666 sortedDie = drawOrder[index];
667 for (otherIndex = index - 1;
668 otherIndex >= 0 && diceWork->
particles[drawOrder[otherIndex]].
z >
671 drawOrder[otherIndex + 1] = drawOrder[otherIndex];
673 drawOrder[otherIndex + 1] = sortedDie;
676 for (index = 0; index !=
DICE_COUNT; index++) {
680 rollingDie = &diceWork->
particles[drawOrder[index]];
685 if (screen[2] < 0x15e) {
688 if (screen[2] > 0x28a) {
691 spriteDepth[drawOrder[index]] = screen[2] - 0x15e;
692 halfSize = 0x800 / (spriteDepth[drawOrder[index]] / 2 + 128);
693 dieX = screen[0] - halfSize;
694 dieY = screen[1] - halfSize;
698 if (dieY + 96 > -16) {
700 ((drawOrder[index] << 25) | (((dieX + 0x278) & 0x1ff) << 16) |
701 ((dieY + 0x160) & 255)) |
711 for (index = 0; index !=
DICE_COUNT; index++) {
713 x = screen[0] - 0x800 / (spriteDepth[drawOrder[index]] / 2 + 128);
714 y = screen[1] + 0x300 / (spriteDepth[drawOrder[index]] / 2 + 128);
716 ((((
x + 0x278) & 0x1ff) << 16) | ((
y + 0x160) & 255)) | 0x80002000;
718 sprites->
obj[spriteCount].
attr01 |= 0x10000000;
720 sprites->
obj[spriteCount].
attr2 = 0x958;
725 for (index = 0; index !=
DICE_COUNT; index++) {
734 if (screen[2] < 0x15e) {
737 if (screen[2] > 0x28a) {
740 spriteDepth[2 + index] = screen[2] - 0x15e;
741 spriteDepth[2 + index] += diceWork->
particles[index].
y >> 16;
744 if (shadowY + 88 > -16) {
746 (((index + 2) << 25) | (((shadowX + 0x270) & 0x1ff) << 16)) |
747 ((shadowY + 0x158) & 255) | 0x40002300;
748 sprites->
obj[spriteCount].
attr2 = 0x890;
758 for (index = 0; index !=
DICE_COUNT; index++) {
759 rollingDie = &diceWork->
particles[index];
764 for (otherIndex = 0; otherIndex !=
DICE_COUNT; otherIndex++) {
765 otherDie = &diceWork->
particles[otherIndex];
766 if (index != otherIndex) {
767 separationX = (rollingDie->
x - otherDie->
x) >> 16;
768 separationY = (rollingDie->
y - otherDie->
y) >> 16;
769 separationZ = (rollingDie->
z - otherDie->
z) >> 16;
770 if (separationX * separationX + separationY * separationY +
771 separationZ * separationZ <=
773 separation =
Iwram_Sqrt(separationX * separationX +
774 separationY * separationY +
775 separationZ * separationZ);
780 if (separation != 0) {
781 rollingDie->
velocityX += separationX * 32768 / separation;
782 rollingDie->
velocityY += separationY * 32768 / separation;
783 rollingDie->
velocityZ += separationZ * 32768 / separation;
786 rollingDie->
velocityX += (separationX << 15) / separation;
787 rollingDie->
velocityY += (separationY << 15) / separation;
788 rollingDie->
velocityZ += (separationZ << 15) / separation;
794 if (rollingDie->
x < -0xc80000) {
795 rollingDie->
x = -0xc80000;
798 if (rollingDie->
x > 0xc80000) {
799 rollingDie->
x = 0xc80000;
802 if (rollingDie->
z < -0x960000) {
803 rollingDie->
z = -0x960000;
806 if (rollingDie->
z > rollingDie->
y + 0xb40000) {
807 rollingDie->
z = rollingDie->
y + 0xb40000;
817 if (rollingDie->
y <= 0) {
824 bounceVelocityX = rollingDie->
velocityX >> 8;
825 bounceVelocityZ = rollingDie->
velocityZ >> 8;
826 bounceSpeed =
Iwram_Sqrt(bounceVelocityX * bounceVelocityX +
827 bounceVelocityZ * bounceVelocityZ) *
836 if (spinRate[index] > 19) {
837 spinRate[index] -= 20;
842 rollAngle = rollingDie->
variant;
843 faceTile = rollAngle / 1024 % 3;
845 rollingDie->
variant = rollAngle + 0x800;
846 }
else if (faceTile == 2) {
847 rollingDie->
variant = rollAngle + 0x400;
855 rollingDie->
variant += spinRate[index];
856 if (rollingDie->
variant > 0x47ff) {
859 if (spinRate[index] > 0) {
864 rollingDie->
velocityZ == 0 && rollingDie->
y == 0) {
865 numbers[index] = rollingDie->
variant / 0xc00;
875 if (rollingDie->
z > rowDepth) {
876 numbers[index + 2] = otherIndex;
891 if (numbers[0] == numbers[1] && numbers[0] == numbers[2] &&
892 numbers[0] == numbers[3]) {
893 flashTimer[0] = flashTimer[1] = 120;
895 if (numbers[0] == luckyNumbers[0]) {
897 }
else if (numbers[0] == luckyNumbers[1]) {
907 for (index = 0; index != 3; index++) {
910 if (numbers[index] == numbers[otherIndex]) {
911 matchedNumbers[pairCount] = numbers[index];
916 if (pairCount == 1) {
922 if (pairCount == 2) {
930 if (pairCount == 3) {
945 for (; spriteCount != 128; spriteCount++) {
946 sprites->
obj[spriteCount].
attr01 = 0x40f02000;
947 sprites->
obj[spriteCount].
attr2 = 0;
953 affineScale = spriteDepth[index] / 2 + 128;
954 affineA = affineScale;
957 affineD = affineScale;
958 sprites->
obj[index * 4 + 0].
attr2 |= affineA << 16;
959 sprites->
obj[index * 4 + 1].
attr2 |= affineB << 16;
960 sprites->
obj[index * 4 + 2].
attr2 |= affineC << 16;
961 sprites->
obj[index * 4 + 3].
attr2 |= affineD << 16;
971 for (index = 0; index != 17; index++) {
972 scale = 0x10000 - (index << 12);
The battle camera and the presentation's transition, background and affine work.
struct BattleCamera * gCameraWork
BattleEffectWork, the running battle effect's work, and its animation objects.
Calls through a function pointer, by argument count.
static __inline__ s32 Value2(s32(*f)(), s32 a0, s32 a1)
The task scheduler: tasks, their order and the scheduler's state.
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...
The edition's language, for C to compare (LANGUAGE == LANGUAGE_GERMAN).
u32 Party_GetAverageLevelFar(void)
s32 Party_AdjustCoinsFar(s32 amount)
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...
GameState, the game's state: play time, coins, the scene and the leader's position,...
struct GameState gGameState
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_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 OBJ_VRAM0
Sprite tile memory, as pret names it: the 32 KB from 0x06010000.
#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
The IWRAM call layer: the routines the game keeps resident in IWRAM, each at its fixed address,...
static s32 Iwram_RatioMulQ14(s32 divisor, s32 value)
All calls go through this layer.
static s32 Iwram_Sqrt(s32 value)
static s32 Iwram_TransformVector(const void *vector, s32 *result)
The keypad state the VBlank interrupt keeps.
volatile u32 gKeysHeld
Keys down now.
volatile u32 gKeysRepeat
Pressed keys, repeating while held: after 19 frames, then every 6.
#define DICE_BET_PER_LEVEL
UNUSED s32 FixedPoint_Multiply8_8(s32 leftValue, s32 rightValue)
Multiplies two 8.8 fixed-point values, rounding toward zero.
UNUSED s16 Math_ScaleByRatio(s16 numerator, s16 denominator)
Divides two 8.8 fixed-point values.
LuckyDiceState
What the Lucky Dice screen is doing.
@ LUCKY_DICE_RESULT
the four numbers and the result are shown
@ LUCKY_DICE_ROLL
the dice fly, bounce and settle
@ LUCKY_DICE_AIM
the dice wait to be thrown; Up and Down raise them
@ LUCKY_DICE_PAYOUT
the winnings move into the coins
void LuckyDice_Run(void)
Runs the Lucky Dice minigame until the player quits or cannot afford a throw.
#define DICE_RESULT_COUNT
s32 Runtime_BlankDisplayAndRun(void)
Starts the Lucky Dice minigame: leaves only the backdrop on screen, starts song MUS_009 and plays unt...
UNUSED s16 FixedPoint_Reciprocal(s16 value)
The reciprocal of an 8.8 fixed-point value.
void Camera_ResetSceneDefaults(void)
Puts the 3D camera back at its scene defaults: at the origin, unturned, pitched to 152 and 510 units ...
s32 Graphics_ScaleRgb555Buffer(u16 *source, u16 *destination, s32 scale, s32 count)
Copies count RGB555 colours from source to destination with each channel multiplied by scale (16....
Small statement macros both games use for positions, velocities and bounds.
#define SET_VELOCITY(p, vx, vy, vz)
#define SET_VECTOR(v, x, y, z)
Sets the x, y and z of a three-part vector: a position about to be projected, a per-frame step,...
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.
struct Projection gProjection
The work pointers in the gWorkSlot table, by name.
#define Ram_MapCellBuffer
Resource numbers, named where their contents are known.
char ResourceId_LuckyDiceBoard
char ResourceId_LuckyDiceSprites
char ResourceId_EffectFarCalls
s32 Resource_DecodeType01(const void *source, void *destination)
Decodes a type-01 resource and returns its unpacked byte count.
FIELD_AT_OFFSET and the entity and camera views older scene code reads.
void Scheduler_ResetTaskTable(void)
Empties the task table: every slot gets no routine, order 0xffff (sorted last) and no flags.
Song and sound effect ids, indices into gSound_SongTable.
The battle camera: its eye, the focus it turns about, and its pitch, yaw and distance.
s32 distance
eye to focus, 16.16 fixed-point pixels
s32 * followPos
when set, the focus followed instead of pos
s32 pos[3]
the focus, 16.16 fixed-point pixels
s32 eye[3]
The eye, 16.16 fixed-point pixels: written each frame distance behind the focus along the turned view...
s32 unk18
cleared beside followPos; not read by name in TBS
The running battle effect's work: its canvas image, 64 particles, the display registers it stages and...
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 z
16.16 fixed-point pixels
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
s32 velocityZ
16.16 fixed-point pixels per frame
The used prefix of Lucky Dice's 0x618-byte work block (heap slot 45): its sprites and windows.
struct UiWindow * coinsWindow
the player's coins
u8 filler[200]
Lucky Dice never touches these bytes.
struct UiWindow * winningsWindow
the winnings of the last throw
struct OamShadow obj[128]
copied to OAM each frame
struct UiWindow * helpWindow
the Throw and Quit buttons
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
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.
The Lucky Dice minigame's tables, after LuckyDice_Run in both games.
const u8 gLuckyDice_LabelTiles[]
The first tile of each kind of result's lettering.
const s16 gLuckyDice_FaceHeights[]
The heights that decide the face (z > value << 16).
const u8 gLuckyDice_LabelCounts[]
How many sprites each kind of result's lettering takes.
const u8 gLuckyDice_FaceTiles[]
The die face tile at each step of its roll.
The integer types, TRUE, UNUSED and the fixed-address macros.
UiWork, the window system's work, and the status screen's cursors.
The patch levels: our groups of the measured changes from the Japanese release.