mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-29 13:50:42 +01:00
7801 lines
236 KiB
C
7801 lines
236 KiB
C
#include "global.h"
|
|
#include "overworld.h"
|
|
#include "field_effect.h"
|
|
#include "random.h"
|
|
#include "sound.h"
|
|
#include "main.h"
|
|
#include "slot_machine.h"
|
|
#include "string_util.h"
|
|
#include "decompress.h"
|
|
#include "trig.h"
|
|
#include "graphics.h"
|
|
#include "palette.h"
|
|
#include "util.h"
|
|
#include "text.h"
|
|
#include "menu.h"
|
|
#include "malloc.h"
|
|
#include "bg.h"
|
|
#include "gpu_regs.h"
|
|
#include "coins.h"
|
|
#include "strings.h"
|
|
#include "tv.h"
|
|
#include "text_window.h"
|
|
#include "main_menu.h"
|
|
#include "bg.h"
|
|
#include "window.h"
|
|
#include "constants/coins.h"
|
|
#include "constants/rgb.h"
|
|
#include "constants/slot_machine.h"
|
|
#include "constants/songs.h"
|
|
|
|
#define SLOTMACHINE_GFX_TILES 233
|
|
#define MAX_BET 3
|
|
|
|
#define SYMBOLS_PER_REEL 21
|
|
#define REEL_SYMBOL_HEIGHT 24
|
|
#define REEL_HEIGHT (SYMBOLS_PER_REEL * REEL_SYMBOL_HEIGHT)
|
|
|
|
#define REELTIME_SYMBOLS 6
|
|
#define REELTIME_SYMBOL_HEIGHT 20
|
|
#define REELTIME_REEL_HEIGHT (REELTIME_SYMBOLS * REELTIME_SYMBOL_HEIGHT)
|
|
|
|
// There are three categories of biases: 7's, ReelTime, Regular
|
|
// - 7's: BIAS_STRAIGHT_7, BIAS_MIXED_7
|
|
// - ReelTime: BIAS_REELTIME
|
|
// - Regular: everything else
|
|
//
|
|
// The 7's and ReelTime biases can be grouped together as 'Special' biases.
|
|
//
|
|
// There can be at most two biases at a time. If there are two, one bias will be
|
|
// ReelTime and the other will be one of the Regular biases.
|
|
//
|
|
// A new bias is drawn every round, except during ReelTime. Bias towards 7's
|
|
// persists across rounds until you match 7's. All other biases are reset after
|
|
// the round.
|
|
#define BIAS_REPLAY (1 << 0)
|
|
#define BIAS_CHERRY (1 << 1)
|
|
#define BIAS_LOTAD (1 << 2)
|
|
#define BIAS_AZURILL (1 << 3)
|
|
#define BIAS_POWER (1 << 4)
|
|
#define BIAS_REELTIME (1 << 5)
|
|
#define BIAS_MIXED_7 (1 << 6)
|
|
#define BIAS_STRAIGHT_7 (1 << 7)
|
|
|
|
#define BIAS_7 (BIAS_STRAIGHT_7 | BIAS_MIXED_7)
|
|
#define BIAS_SPECIAL (BIAS_7 | BIAS_REELTIME)
|
|
#define BIAS_REGULAR (BIAS_REPLAY | BIAS_CHERRY | BIAS_LOATAD | BIAS_AZURILL | BIAS_POWER)
|
|
|
|
// The slot machine will try to manipulate the outcome by adding up to 4 extra
|
|
// turns to the reel after you press stop.
|
|
//
|
|
// The only exception is when it is stopping the third reel and it has decided
|
|
// you will lose. In this case, it adds as many turns as necessary to prevent a
|
|
// match.
|
|
#define MAX_EXTRA_TURNS 4
|
|
|
|
enum {
|
|
SYMBOL_7_RED,
|
|
SYMBOL_7_BLUE,
|
|
SYMBOL_AZURILL,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_CHERRY,
|
|
SYMBOL_POWER,
|
|
SYMBOL_REPLAY,
|
|
};
|
|
|
|
enum
|
|
{
|
|
GFXTAG_7_RED,
|
|
GFXTAG_7_BLUE,
|
|
GFXTAG_AZURILL,
|
|
GFXTAG_LOTAD,
|
|
GFXTAG_CHERRY,
|
|
GFXTAG_POWER,
|
|
GFXTAG_REPLAY,
|
|
GFXTAG_NUM_0,
|
|
GFXTAG_NUM_1,
|
|
GFXTAG_NUM_2,
|
|
GFXTAG_NUM_3,
|
|
GFXTAG_NUM_4,
|
|
GFXTAG_NUM_5,
|
|
GFXTAG_NUM_6,
|
|
GFXTAG_NUM_7,
|
|
GFXTAG_NUM_8,
|
|
GFXTAG_NUM_9,
|
|
GFXTAG_REEL_BG,
|
|
GFXTAG_STOP,
|
|
GFXTAG_BONUS,
|
|
GFXTAG_BIG,
|
|
GFXTAG_REG,
|
|
};
|
|
|
|
#define GFXTAG_SYMBOLS_START (GFXTAG_7_RED)
|
|
#define GFXTAG_NUMBERS_START (GFXTAG_NUM_0)
|
|
|
|
#define REEL_NORMAL_SPEED 8
|
|
#define REEL_HALF_SPEED 4
|
|
#define REEL_QUARTER_SPEED 2
|
|
|
|
enum {
|
|
PALTAG_REEL,
|
|
PALTAG_REEL_TIME_PIKACHU,
|
|
PALTAG_REEL_TIME_MISC,
|
|
PALTAG_REEL_TIME_MACHINE,
|
|
PALTAG_MISC,
|
|
PALTAG_EXPLOSION,
|
|
PALTAG_DIG_DISPLAY,
|
|
PALTAG_PIKA_AURA,
|
|
};
|
|
|
|
enum {
|
|
MATCH_CHERRY, // Cherry in center of first reel
|
|
MATCH_TOPBOT_CHERRY, // Cherry in top/bottom of first reel
|
|
MATCH_REPLAY,
|
|
MATCH_LOTAD,
|
|
MATCH_AZURILL,
|
|
MATCH_POWER,
|
|
MATCH_MIXED_7, // First two 7's are same color; last is other color
|
|
MATCH_RED_7,
|
|
MATCH_BLUE_7,
|
|
MATCH_NONE,
|
|
};
|
|
|
|
enum {
|
|
MATCH_MIDDLE_ROW,
|
|
MATCH_TOP_ROW,
|
|
MATCH_BOTTOM_ROW,
|
|
MATCH_NWSE_DIAG,
|
|
MATCH_NESW_DIAG,
|
|
NUM_MATCH_LINES,
|
|
};
|
|
|
|
enum {
|
|
LEFT_REEL,
|
|
MIDDLE_REEL,
|
|
RIGHT_REEL,
|
|
NUM_REELS,
|
|
};
|
|
|
|
enum {
|
|
SLOTTASK_UNFADE,
|
|
SLOTTASK_WAIT_FADE,
|
|
SLOTTASK_READY_NEW_SPIN,
|
|
SLOTTASK_READY_NEW_RT_SPIN,
|
|
SLOTTASK_ASK_INSERT_BET,
|
|
SLOTTASK_BET_INPUT,
|
|
SLOTTASK_MSG_NEED_3_COINS,
|
|
SLOTTASK_WAIT_MSG_NEED_3_COINS,
|
|
SLOTTASK_WAIT_INFO_BOX,
|
|
SLOTTASK_START_SPIN,
|
|
SLOTTASK_START_RT_SPIN,
|
|
SLOTTASK_RESET_BIAS_FAILURE,
|
|
SLOTTASK_WAIT_REEL_STOP,
|
|
SLOTTASK_WAIT_ALL_REELS_STOP,
|
|
SLOTTASK_CHECK_MATCHES,
|
|
SLOTTASK_WAIT_PAYOUT,
|
|
SLOTTASK_END_PAYOUT,
|
|
SLOTTASK_MATCHED_POWER,
|
|
SLOTTASK_WAIT_RT_ANIM,
|
|
SLOTTASK_RESET_BET_TILES,
|
|
SLOTTASK_NO_MATCHES,
|
|
SLOTTASK_ASK_QUIT,
|
|
SLOTTASK_HANDLE_QUIT_INPUT,
|
|
SLOTTASK_MSG_MAX_COINS,
|
|
SLOTTASK_WAIT_MSG_MAX_COINS,
|
|
SLOTTASK_MSG_NO_MORE_COINS,
|
|
SLOTTASK_WAIT_MSG_NO_MORE_COINS,
|
|
SLOTTASK_END,
|
|
SLOTTASK_FREE,
|
|
};
|
|
enum
|
|
{
|
|
PAYOUT_TASK_INIT,
|
|
PAYOUT_TASK_GIVE_PAYOUT,
|
|
PAYOUT_TASK_FREE,
|
|
};
|
|
|
|
enum {
|
|
REEL_TASK_STILL,
|
|
REEL_TASK_SPIN,
|
|
REEL_TASK_DECIDE_STOP,
|
|
REEL_TASK_STOP_MOVE,
|
|
REEL_TASK_STOP_SHAKE,
|
|
};
|
|
|
|
enum {
|
|
PIKABOLT_TASK_IDLE,
|
|
PIKABOLT_TASK_ADD_BOLT,
|
|
PIKABOLT_TASK_WAIT_ANIM,
|
|
PIKABOLT_TASK_CLEAR_ALL,
|
|
};
|
|
|
|
enum {
|
|
RT_TASK_INIT,
|
|
RT_TASK_WINDOW_ENTER,
|
|
RT_TASK_WAIT_START_PIKA,
|
|
RT_TASK_PIKA_SPEEDUP1,
|
|
RT_TASK_PIKA_SPEEDUP2,
|
|
RT_TASK_WAIT_REEL,
|
|
RT_TASK_CHECK_EXPLODE,
|
|
RT_TASK_LAND,
|
|
RT_TASK_PIKA_REACT,
|
|
RT_TASK_WAIT_CLEAR_POWER,
|
|
RT_TASK_CLOSE_WINDOW_SUCCESS,
|
|
RT_TASK_DESTROY_SPRITES,
|
|
RT_TASK_SET_REEL_SPEED,
|
|
RT_TASK_END_SUCCESS,
|
|
RT_TASK_EXPLODE,
|
|
RT_TASK_WAIT_EXPLODE,
|
|
RT_TASK_WAIT_SMOKE,
|
|
RT_TASK_CLOSE_WINDOW_FAILURE,
|
|
RT_TASK_END_FAILURE,
|
|
};
|
|
|
|
#define DIG_SPRITE_DUMMY {255, 0, 0}
|
|
|
|
// Sprite template IDs for the digital display in the right panel
|
|
enum {
|
|
DIG_SPRITE_REEL,
|
|
DIG_SPRITE_TIME,
|
|
DIG_SPRITE_INSERT,
|
|
DIG_SPRITE_WIN,
|
|
DIG_SPRITE_LOSE,
|
|
DIG_SPRITE_A_BUTTON,
|
|
DIG_SPRITE_SMOKE,
|
|
DIG_SPRITE_NUMBER,
|
|
DIG_SPRITE_POKE_BALL,
|
|
DIG_SPRITE_D_PAD,
|
|
DIG_SPRITE_STOP_S,
|
|
DIG_SPRITE_STOP_T,
|
|
DIG_SPRITE_STOP_O,
|
|
DIG_SPRITE_STOP_P,
|
|
DIG_SPRITE_BONUS_B,
|
|
DIG_SPRITE_BONUS_O,
|
|
DIG_SPRITE_BONUS_N,
|
|
DIG_SPRITE_BONUS_U,
|
|
DIG_SPRITE_BONUS_S,
|
|
DIG_SPRITE_BIG_B,
|
|
DIG_SPRITE_BIG_I,
|
|
DIG_SPRITE_BIG_G,
|
|
DIG_SPRITE_REG_R,
|
|
DIG_SPRITE_REG_E,
|
|
DIG_SPRITE_REG_G,
|
|
DIG_SPRITE_EMPTY,
|
|
NUM_DIG_DISPLAY_SPRITES
|
|
};
|
|
|
|
// IDs used by the digital display to set coords and callbacks for its sprites
|
|
enum {
|
|
DIG_DISPINFO_INSERT,
|
|
DIG_DISPINFO_STOP_S,
|
|
DIG_DISPINFO_STOP_T,
|
|
DIG_DISPINFO_STOP_O,
|
|
DIG_DISPINFO_STOP_P,
|
|
DIG_DISPINFO_A_BUTTON_STOP,
|
|
DIG_DISPINFO_POKE_BALL_ROCKING,
|
|
DIG_DISPINFO_WIN,
|
|
DIG_DISPINFO_LOSE,
|
|
DIG_DISPINFO_SMOKE_NW,
|
|
DIG_DISPINFO_SMOKE_NE,
|
|
DIG_DISPINFO_SMOKE_SW,
|
|
DIG_DISPINFO_SMOKE_SE,
|
|
DIG_DISPINFO_REEL,
|
|
DIG_DISPINFO_TIME,
|
|
DIG_DISPINFO_NUMBER,
|
|
DIG_DISPINFO_DPAD,
|
|
DIG_DISPINFO_POKE_BALL_SHINING,
|
|
DIG_DISPINFO_REG_R,
|
|
DIG_DISPINFO_REG_E,
|
|
DIG_DISPINFO_REG_G,
|
|
DIG_DISPINFO_REG_BONUS_B,
|
|
DIG_DISPINFO_REG_BONUS_O,
|
|
DIG_DISPINFO_REG_BONUS_N,
|
|
DIG_DISPINFO_REG_BONUS_U,
|
|
DIG_DISPINFO_REG_BONUS_S,
|
|
DIG_DISPINFO_BIG_B,
|
|
DIG_DISPINFO_BIG_I,
|
|
DIG_DISPINFO_BIG_G,
|
|
DIG_DISPINFO_BIG_BONUS_B,
|
|
DIG_DISPINFO_BIG_BONUS_O,
|
|
DIG_DISPINFO_BIG_BONUS_N,
|
|
DIG_DISPINFO_BIG_BONUS_U,
|
|
DIG_DISPINFO_BIG_BONUS_S,
|
|
DIG_DISPINFO_A_BUTTON_START
|
|
};
|
|
|
|
// IDs for digital display "scenes", i.e. each of the screens it can show made up of sprites
|
|
enum {
|
|
DIG_DISPLAY_INSERT_BET,
|
|
DIG_DISPLAY_STOP_REEL,
|
|
DIG_DISPLAY_WIN,
|
|
DIG_DISPLAY_LOSE,
|
|
DIG_DISPLAY_REEL_TIME,
|
|
DIG_DISPLAY_BONUS_REG,
|
|
DIG_DISPLAY_BONUS_BIG
|
|
};
|
|
|
|
|
|
// How ReelTime works
|
|
// ==================
|
|
// Entering ReelTime:
|
|
// - If the bias you draw at the start of the round is BIAS_REELTIME, the
|
|
// ReelTime lottery begins.
|
|
// - At the start of the lottery, the game selects how many ReelTime spins you
|
|
// will get, based on how many Power bolts you've collected and whether it
|
|
// is a lucky game.
|
|
// - The lottery machine rolls until it lands on the selected number. If it
|
|
// selected 0 spins, the lottery machine will mostly likely explode before
|
|
// landing on 0.
|
|
// - If you win:
|
|
// - You receive the selected number of ReelTime spins
|
|
// - You lose all the Power bolts you've collected thus far
|
|
// - The lottery window closes and ReelTime officially begins
|
|
//
|
|
// During ReelTime:
|
|
// - You still have to pay coins for bets.
|
|
// - The slot reels may spin slower than usual in ReelTime. The machine draws a
|
|
// reel speed at the beginning of each ReelTime spin. The more coins you've
|
|
// lost to the machine, and the more consecutive ReelTime spins you've done,
|
|
// the higher your chances of getting a slower reel speed.
|
|
// - In ReelTime, the reel stops exactly on your input. That is, it won't add
|
|
// extra turns to manipulate the outcome.
|
|
// - ReelTime ends early if you win red 7's or blue 7's.
|
|
|
|
|
|
// SlotMachine field explanations:
|
|
//
|
|
// luckyGame:
|
|
// Determined at random when you start playing. Some events modify this:
|
|
// - Blue 7 match: game becomes lucky
|
|
// - Red 7 match: game becomes normal
|
|
//
|
|
// Effectively, a lucky game inreases the odds of getting more ReelTime spins.
|
|
// If the game is lucky, you have a slightly higher chance of matching Power
|
|
// bolts (at the expense of Replays). This helps you fill your Power bolt
|
|
// gauge faster.
|
|
//
|
|
// During ReelTime, the more Power bolts you have, the greater your chances
|
|
// of drawing more ReelTime spins. In a lucky game, you have greater odds of
|
|
// drawing high yields (3+ RT spins). You also have greater odds of drawing 0
|
|
// RT spins. But drawing 0 lets you keep all your Power bolts, allowing you to
|
|
// fill your gauge further.
|
|
struct SlotMachine
|
|
{
|
|
/*0x00*/ u8 state;
|
|
/*0x01*/ u8 machineId;
|
|
/*0x02*/ u8 pikaPowerBolts;
|
|
/*0x03*/ bool8 luckyGame;
|
|
/*0x04*/ u8 machineBias;
|
|
/*0x05*/ u8 reelTimeDraw;
|
|
/*0x06*/ bool8 didNotFailBias;
|
|
/*0x07*/ u8 biasSymbol;
|
|
/*0x08*/ u16 matches;
|
|
/*0x0A*/ u8 reelTimeSpinsLeft;
|
|
/*0x0B*/ u8 reelTimeSpinsUsed;
|
|
/*0x0C*/ s16 coins;
|
|
/*0x0E*/ s16 payout;
|
|
/*0x10*/ s16 netCoinLoss; // never negative
|
|
/*0x12*/ s16 bet;
|
|
/*0x14*/ s16 reeltimePixelOffset;
|
|
/*0x16*/ s16 reeltimePosition;
|
|
/*0x18*/ s16 currentReel;
|
|
/*0x1A*/ s16 reelSpeed;
|
|
/*0x1C*/ s16 reelPixelOffsets[NUM_REELS];
|
|
/*0x22*/ u16 reelShockOffsets[NUM_REELS];
|
|
/*0x28*/ s16 reelPositions[NUM_REELS];
|
|
/*0x2E*/ s16 reelExtraTurns[NUM_REELS];
|
|
/*0x34*/ s16 winnerRows[NUM_REELS];
|
|
/*0x3A*/ u8 slotReelTasks[NUM_REELS];
|
|
/*0x3D*/ u8 digDisplayTaskId;
|
|
/*0x3E*/ u8 pikaPowerBoltTaskId;
|
|
/*0x3F*/ u8 reelTimePikachuSpriteId;
|
|
/*0x40*/ u8 reelTimeNumberGapSpriteId;
|
|
/*0x41*/ u8 reelTimeExplosionSpriteId;
|
|
/*0x42*/ u8 reelTimeBrokenMachineSpriteId;
|
|
/*0x43*/ u8 reelTimeSmokeSpriteId;
|
|
/*0x44*/ u8 flashMatchLineSpriteIds[NUM_MATCH_LINES];
|
|
/*0x49*/ u8 reelTimeMachineSpriteIds[2];
|
|
/*0x49*/ u8 reelTimeNumberSpriteIds[3];
|
|
/*0x4E*/ u8 reelTimeShadowSpriteIds[2];
|
|
/*0x50*/ u8 reelTimeBoltSpriteIds[2];
|
|
/*0x52*/ u8 reelTimePikachuAuraSpriteIds[2];
|
|
/*0x54*/ u8 reelTimeDuckSpriteIds[4];
|
|
/*0x58*/ u16 win0h;
|
|
/*0x5a*/ u16 win0v;
|
|
/*0x5c*/ u16 winIn;
|
|
/*0x5e*/ u16 winOut;
|
|
/*0x60*/ u16 backupMapMusic;
|
|
/*0x64*/ MainCallback prevMainCb;
|
|
};
|
|
|
|
struct DigitalDisplaySprite
|
|
{
|
|
/*0x00*/ u8 spriteTemplateId;
|
|
/*0x01*/ u8 dispInfoId;
|
|
/*0x02*/ s16 spriteId;
|
|
};
|
|
|
|
static void CB2_SlotMachineSetup(void);
|
|
static void CB2_SlotMachine(void);
|
|
static void PlaySlotMachine_Internal(u8, MainCallback);
|
|
static void SlotMachineDummyTask(u8);
|
|
static void SlotMachineSetup_InitBgsWindows(void);
|
|
static void SlotMachineSetup_InitVRAM(void);
|
|
static void SlotMachineSetup_InitOAM(void);
|
|
static void SlotMachineSetup_InitGpuRegs(void);
|
|
static void InitSlotMachine(void);
|
|
static void SlotMachineSetup_InitPalsSpritesTasks(void);
|
|
static void SlotMachineSetup_InitTilemaps(void);
|
|
static void SlotMachineSetup_LoadGfxAndTilemaps(void);
|
|
static void SlotMachineSetup_InitVBlank(void);
|
|
static void AllocDigitalDisplayGfx(void);
|
|
static void SetDigitalDisplayImagePtrs(void);
|
|
static void CreateSlotMachineSprites(void);
|
|
static void CreateGameplayTasks(void);
|
|
static void CreateSlotMachineTasks(void);
|
|
static void DestroyDigitalDisplayScene(void);
|
|
static void Task_SlotMachine(u8);
|
|
static bool8 SlotTask_UnfadeScreen(struct Task *);
|
|
static bool8 SlotTask_WaitUnfade(struct Task *);
|
|
static bool8 SlotTask_ReadyNewSpin(struct Task *);
|
|
static bool8 SlotTask_ReadyNewReelTimeSpin(struct Task *);
|
|
static bool8 SlotTask_AskInsertBet(struct Task *);
|
|
static bool8 SlotTask_HandleBetInput(struct Task *);
|
|
static bool8 SlotTask_PrintMsg_Need3Coins(struct Task *);
|
|
static bool8 SlotTask_WaitMsg_Need3Coins(struct Task *);
|
|
static bool8 SlotTask_WaitInfoBox(struct Task *);
|
|
static bool8 SlotTask_StartSpin(struct Task *);
|
|
static bool8 SlotTask_StartReelTimeSpin(struct Task *);
|
|
static bool8 SlotTask_ResetBiasFailure(struct Task *);
|
|
static bool8 SlotTask_WaitReelStop(struct Task *);
|
|
static bool8 SlotTask_WaitAllReelsStop(struct Task *);
|
|
static bool8 SlotTask_CheckMatches(struct Task *);
|
|
static bool8 SlotTask_WaitPayout(struct Task *);
|
|
static bool8 SlotTask_EndPayout(struct Task *);
|
|
static bool8 SlotTask_MatchedPower(struct Task *);
|
|
static bool8 SlotTask_WaitReelTimeAnim(struct Task *);
|
|
static bool8 SlotTask_ResetBetTiles(struct Task *);
|
|
static bool8 SlotTask_NoMatches(struct Task *);
|
|
static bool8 SlotTask_AskQuit(struct Task *);
|
|
static bool8 SlotTask_HandleQuitInput(struct Task *);
|
|
static bool8 SlotTask_PrintMsg_MaxCoins(struct Task *);
|
|
static bool8 SlotTask_WaitMsg_MaxCoins(struct Task *);
|
|
static bool8 SlotTask_PrintMsg_NoMoreCoins(struct Task *);
|
|
static bool8 SlotTask_WaitMsg_NoMoreCoins(struct Task *);
|
|
static bool8 SlotTask_EndGame(struct Task *);
|
|
static bool8 SlotTask_FreeDataStructures(struct Task *);
|
|
static void DrawMachineBias(void);
|
|
static void ResetBiasFailure(void);
|
|
static bool8 ShouldTrySpecialBias(void);
|
|
static u8 TrySelectBias_Special(void);
|
|
static u16 ReelTimeSpeed(void);
|
|
static u8 TrySelectBias_Regular(void);
|
|
static void CheckMatch(void);
|
|
static void CheckMatch_CenterRow(void);
|
|
static void CheckMatch_TopAndBottom(void);
|
|
static void CheckMatch_Diagonals(void);
|
|
static u8 GetMatchFromSymbols(u8, u8, u8);
|
|
static void AwardPayout(void);
|
|
static void Task_Payout(u8);
|
|
static bool8 IsFinalTask_Task_Payout(void);
|
|
static bool8 PayoutTask_Init(struct Task *);
|
|
static bool8 PayoutTask_GivePayout(struct Task *);
|
|
static bool8 PayoutTask_Free(struct Task *);
|
|
static u8 GetSymbolAtRest(u8, s16);
|
|
static void CreateReelTasks(void);
|
|
static void SpinSlotReel(u8);
|
|
static void StopSlotReel(u8);
|
|
static bool8 IsSlotReelMoving(u8);
|
|
static void Task_Reel(u8);
|
|
static bool8 ReelTask_StayStill(struct Task *);
|
|
static bool8 ReelTask_Spin(struct Task *);
|
|
static bool8 ReelTask_DecideStop(struct Task *);
|
|
static bool8 ReelTask_MoveToStop(struct Task *);
|
|
static bool8 ReelTask_ShakingStop(struct Task *);
|
|
static bool8 DecideStop_Bias_Reel1(void);
|
|
static bool8 DecideStop_Bias_Reel1_Bet1(u8, u8);
|
|
static bool8 DecideStop_Bias_Reel1_Bet2or3(u8, u8);
|
|
static bool8 DecideStop_Bias_Reel2(void);
|
|
static bool8 DecideStop_Bias_Reel2_Bet1or2(void);
|
|
static bool8 DecideStop_Bias_Reel2_Bet3(void);
|
|
static bool8 DecideStop_Bias_Reel3(void);
|
|
static bool8 DecideStop_Bias_Reel3_Bet1or2(u8);
|
|
static bool8 DecideStop_Bias_Reel3_Bet3(u8);
|
|
static void DecideStop_NoBias_Reel1(void);
|
|
static void DecideStop_NoBias_Reel2(void);
|
|
static void DecideStop_NoBias_Reel2_Bet1(void);
|
|
static void DecideStop_NoBias_Reel2_Bet2(void);
|
|
static void DecideStop_NoBias_Reel2_Bet3(void);
|
|
static void DecideStop_NoBias_Reel3(void);
|
|
static void DecideStop_NoBias_Reel3_Bet1(void);
|
|
static void DecideStop_NoBias_Reel3_Bet2(void);
|
|
static void DecideStop_NoBias_Reel3_Bet3(void);
|
|
static void PressStopReelButton(u8);
|
|
static void Task_PressStopReelButton(u8);
|
|
static void LightenBetTiles(u8);
|
|
static void StopReelButton_Press(struct Task *, u8);
|
|
static void StopReelButton_Wait(struct Task *, u8);
|
|
static void StopReelButton_Unpress(struct Task *, u8);
|
|
static void DarkenBetTiles(u8);
|
|
static void CreateInvisibleFlashMatchLineSprites(void);
|
|
static void FlashMatchLine(u8);
|
|
static bool8 IsMatchLineDoneFlashingBeforePayout(void);
|
|
static bool8 TryStopMatchLinesFlashing(void);
|
|
static bool8 TryStopMatchLineFlashing(u8);
|
|
static void SpriteCB_FlashMatchingLines(struct Sprite *);
|
|
static void FlashSlotMachineLights(void);
|
|
static bool8 TryStopSlotMachineLights(void);
|
|
static void Task_FlashSlotMachineLights(u8);
|
|
static void CreatePikaPowerBoltTask(void);
|
|
static void AddPikaPowerBolt(u8);
|
|
static bool8 IsPikaPowerBoltAnimating(void);
|
|
static void Task_CreatePikaPowerBolt(u8);
|
|
static void PikaPowerBolt_Idle(struct Task *);
|
|
static void PikaPowerBolt_AddBolt(struct Task *);
|
|
static void PikaPowerBolt_WaitAnim(struct Task *);
|
|
static void PikaPowerBolt_ClearAll(struct Task *);
|
|
static void ResetPikaPowerBoltTask(struct Task *);
|
|
static void LoadPikaPowerMeter(u8 );
|
|
static void BeginReelTime(void);
|
|
static bool8 IsReelTimeTaskDone(void);
|
|
static void Task_ReelTime(u8 );
|
|
static void ReelTime_Init(struct Task *);
|
|
static void ReelTime_WindowEnter(struct Task *);
|
|
static void ReelTime_WaitStartPikachu(struct Task *);
|
|
static void ReelTime_PikachuSpeedUp1(struct Task *);
|
|
static void ReelTime_PikachuSpeedUp2(struct Task *);
|
|
static void ReelTime_WaitReel(struct Task *);
|
|
static void ReelTime_CheckExplode(struct Task *);
|
|
static void ReelTime_LandOnOutcome(struct Task *);
|
|
static void ReelTime_PikachuReact(struct Task *);
|
|
static void ReelTime_WaitClearPikaPower(struct Task *);
|
|
static void ReelTime_CloseWindow(struct Task *);
|
|
static void ReelTime_DestroySprites(struct Task *);
|
|
static void ReelTime_SetReelSpeed(struct Task *);
|
|
static void ReelTime_EndSuccess(struct Task *);
|
|
static void ReelTime_ExplodeMachine(struct Task *);
|
|
static void ReelTime_WaitExplode(struct Task *);
|
|
static void ReelTime_WaitSmoke(struct Task *);
|
|
static void ReelTime_EndFailure(struct Task *);
|
|
static void LoadReelTimeWindowTilemap(s16, s16);
|
|
static void ClearReelTimeWindowTilemap(s16);
|
|
static void OpenInfoBox(u8);
|
|
static bool8 IsInfoBoxClosed(void);
|
|
static void Task_InfoBox(u8 );
|
|
static void InfoBox_FadeIn(struct Task *);
|
|
static void InfoBox_WaitFade(struct Task *);
|
|
static void InfoBox_DrawWindow(struct Task *);
|
|
static void InfoBox_WaitInput(struct Task *);
|
|
static void InfoBox_AddText(struct Task *);
|
|
static void InfoBox_LoadPikaPowerMeter(struct Task *);
|
|
static void InfoBox_LoadSlotMachineTilemap(struct Task *);
|
|
static void InfoBox_CreateDigitalDisplay(struct Task *);
|
|
static void InfoBox_FreeTask(struct Task *);
|
|
static void CreateDigitalDisplayTask(void);
|
|
static void CreateDigitalDisplayScene(u8 );
|
|
static bool8 IsDigitalDisplayAnimFinished(void);
|
|
static void DigitalDisplay_Idle(struct Task *);
|
|
static void Task_DigitalDisplay(u8);
|
|
static void CreateReelSymbolSprites(void);
|
|
static void CreateCreditPayoutNumberSprites(void);
|
|
static void CreateCoinNumberSprite(s16, s16, u8, s16);
|
|
static void CreateReelBackgroundSprite(void);
|
|
static void CreateReelTimePikachuSprite(void);
|
|
static void DestroyReelTimePikachuSprite(void);
|
|
static void CreateReelTimeMachineSprites(void);
|
|
static void CreateBrokenReelTimeMachineSprite(void);
|
|
static void CreateReelTimeNumberSprites(void);
|
|
static void CreateReelTimeShadowSprites(void);
|
|
static void CreateReelTimeNumberGapSprite(void);
|
|
static void DestroyReelTimeMachineSprites(void);
|
|
static void DestroyReelTimeShadowSprites(void);
|
|
static void DestroyBrokenReelTimeMachineSprite(void);
|
|
static void CreateReelTimeBoltSprites(void);
|
|
static void SetReelTimeBoltDelay(s16);
|
|
static void DestroyReelTimeBoltSprites(void);
|
|
static void CreateReelTimePikachuAuraSprites(void);
|
|
static void SetReelTimePikachuAuraFlashDelay(s16);
|
|
static void DestroyReelTimePikachuAuraSprites(void);
|
|
static void CreateReelTimeExplosionSprite(void);
|
|
static void DestroyReelTimeExplosionSprite(void);
|
|
static void CreateReelTimeDuckSprites(void);
|
|
static void DestroyReelTimeDuckSprites(void);
|
|
static void CreateReelTimeSmokeSprite(void);
|
|
static bool8 IsReelTimeSmokeAnimFinished(void);
|
|
static void DestroyReelTimeSmokeSprite(void);
|
|
static u8 CreatePikaPowerBoltSprite(s16, s16);
|
|
static void DestroyPikaPowerBoltSprite(u8);
|
|
static u8 CreateDigitalDisplaySprite(u8, void (*callback)(struct Sprite *), s16, s16, s16);
|
|
static void LoadSlotMachineGfx(void);
|
|
static void LoadReelBackground(void);
|
|
static void LoadMenuGfx(void);
|
|
static void LoadMenuAndReelOverlayTilemaps(void);
|
|
static void SetReelButtonTilemap(s16, u16, u16, u16, u16);
|
|
static void LoadInfoBoxTilemap(void);
|
|
static void LoadSlotMachineMenuTilemap(void);
|
|
static void LoadSlotMachineReelOverlay(void);
|
|
static u8 CreateStdDigitalDisplaySprite(u8, u8, s16);
|
|
static void SpriteCB_DigitalDisplay_Static(struct Sprite *);
|
|
static void SpriteCB_DigitalDisplay_Stop(struct Sprite *);
|
|
static void SpriteCB_DigitalDisplay_AButtonStop(struct Sprite *);
|
|
static void SpriteCB_DigitalDisplay_PokeballRocking(struct Sprite *);
|
|
static void SpriteCB_DigitalDisplay_Smoke(struct Sprite *);
|
|
static void SpriteCB_DigitalDisplay_SmokeNE(struct Sprite *);
|
|
static void SpriteCB_DigitalDisplay_SmokeSW(struct Sprite *);
|
|
static void SpriteCB_DigitalDisplay_SmokeSE(struct Sprite *);
|
|
static void SpriteCB_DigitalDisplay_Reel(struct Sprite *);
|
|
static void SpriteCB_DigitalDisplay_Time(struct Sprite *);
|
|
static void SpriteCB_DigitalDisplay_ReelTimeNumber(struct Sprite *);
|
|
static void SpriteCB_DigitalDisplay_PokeballShining(struct Sprite *);
|
|
static void SpriteCB_DigitalDisplay_RegBonus(struct Sprite *);
|
|
static void SpriteCB_DigitalDisplay_BigBonus(struct Sprite *);
|
|
static void SpriteCB_DigitalDisplay_AButtonStart(struct Sprite *);
|
|
static void EndDigitalDisplayScene_InsertBet(void);
|
|
static void EndDigitalDisplayScene_StopReel(void);
|
|
static void EndDigitalDisplayScene_Win(void);
|
|
static void EndDigitalDisplayScene_Dummy(void);
|
|
static void SpriteCB_ReelSymbol(struct Sprite *);
|
|
static void SpriteCB_CoinNumber(struct Sprite *);
|
|
static void SpriteCB_ReelTimePikachu(struct Sprite *);
|
|
static void SpriteCB_ReelTimeNumbers(struct Sprite *);
|
|
static void SpriteCB_ReelTimeBolt(struct Sprite *);
|
|
static void SpriteCB_ReelTimePikachuAura(struct Sprite *);
|
|
static void SpriteCB_ReelTimeExplosion(struct Sprite *);
|
|
static void SpriteCB_ReelTimeDuck(struct Sprite *);
|
|
static void SpriteCB_ReelTimeSmoke(struct Sprite *);
|
|
static void SpriteCB_PikaPowerBolt(struct Sprite *);
|
|
|
|
// Ewram variables
|
|
static EWRAM_DATA u16 *sMenuGfx = NULL;
|
|
static EWRAM_DATA u16 *sSelectedPikaPowerTile = NULL;
|
|
static EWRAM_DATA u16 *sReelOverlay_Tilemap = NULL;
|
|
static EWRAM_DATA u8 *sDigitalDisplayGfxPtr = NULL;
|
|
static EWRAM_DATA u8 *sReelTimeGfxPtr = NULL;
|
|
static EWRAM_DATA u16 *sReelButtonPress_Tilemap = NULL;
|
|
static EWRAM_DATA u8 *sReelBackground_Gfx = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_ReelTimePikachu = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_ReelTimeMachineAntennae = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_ReelTimeMachine = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_BrokenReelTimeMachine = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_DigitalDisplay_Reel = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_DigitalDisplay_Time = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_DigitalDisplay_Insert = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_DigitalDisplay_Stop = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_DigitalDisplay_Win = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_DigitalDisplay_Lose = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_DigitalDisplay_Bonus = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_DigitalDisplay_Big = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_DigitalDisplay_Reg = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_DigitalDisplay_AButton = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_DigitalDisplay_Smoke = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_DigitalDisplay_Number = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_DigitalDisplay_Pokeball = NULL;
|
|
static EWRAM_DATA struct SpriteFrameImage *sImageTable_DigitalDisplay_DPad = NULL;
|
|
static EWRAM_DATA struct SpriteSheet *sReelBackgroundSpriteSheet = NULL;
|
|
static EWRAM_DATA struct SpriteSheet *sSlotMachineSpritesheetsPtr = NULL;
|
|
static EWRAM_DATA struct SlotMachine *sSlotMachine = NULL;
|
|
|
|
// IWRAM bss
|
|
static struct SpriteFrameImage *sImageTables_DigitalDisplay[NUM_DIG_DISPLAY_SPRITES];
|
|
|
|
// Const rom data.
|
|
static const struct DigitalDisplaySprite *const sDigitalDisplayScenes[];
|
|
static const u16 sUnkPalette[];
|
|
static const u8 sSpecialDrawOdds[NUM_SLOT_MACHINE_IDS][MAX_BET];
|
|
static const u8 sBiasSymbols[];
|
|
static const u16 sBiasesSpecial[3];
|
|
static const u16 sBiasesRegular[5];
|
|
static const s16 sDigitalDisplay_SpriteCoords[][2];
|
|
static const SpriteCallback sDigitalDisplay_SpriteCallbacks[];
|
|
static const struct SpriteTemplate *const sSpriteTemplates_DigitalDisplay[NUM_DIG_DISPLAY_SPRITES];
|
|
static const struct SubspriteTable *const sSubspriteTables_DigitalDisplay[NUM_DIG_DISPLAY_SPRITES];
|
|
static const struct SpriteTemplate sSpriteTemplate_PikaPowerBolt;
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeSmoke;
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeDuck;
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeExplosion;
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimePikachuAura;
|
|
static const u16 sReelTimeExplodeProbability[];
|
|
static const u16 *const sPokeballShiningPalTable[];
|
|
static const u16 sReelTimeSpeed_Probabilities[][2];
|
|
static const u16 sQuarterSpeed_ProbabilityBoost[];
|
|
static const u16 sSlotMatchFlags[];
|
|
static const u16 sSlotPayouts[];
|
|
static const u8 *const sReelBackground_Tilemap;
|
|
static const u32 sReelTimeGfx[];
|
|
static const struct SpriteSheet sSlotMachineSpriteSheets[22];
|
|
static const struct SpritePalette sSlotMachineSpritePalettes[];
|
|
static const u16 *const sDigitalDisplay_Pal;
|
|
static const s16 sInitialReelPositions[NUM_REELS][2];
|
|
static const u8 sBiasProbabilities_Special[][NUM_SLOT_MACHINE_IDS];
|
|
static const u8 sBiasProbabilities_Regular[][NUM_SLOT_MACHINE_IDS];
|
|
static const u8 sReelTimeProbabilities_NormalGame[][17];
|
|
static const u8 sReelTimeProbabilities_LuckyGame[][17];
|
|
static const u8 sSymbolToMatch[];
|
|
static const u8 sReelTimeSymbols[];
|
|
static const u8 sReelSymbols[NUM_REELS][SYMBOLS_PER_REEL];
|
|
static const u16 *const sLitMatchLinePalTable[NUM_MATCH_LINES];
|
|
static const u16 *const sDarkMatchLinePalTable[NUM_MATCH_LINES];
|
|
static const u8 sMatchLinePalOffsets[NUM_MATCH_LINES];
|
|
static const u8 sBetToMatchLineIds[MAX_BET][2];
|
|
static const u8 sMatchLinesPerBet[MAX_BET];
|
|
static const u16 *const sFlashingLightsPalTable[];
|
|
static const u16 *const sSlotMachineMenu_Pal;
|
|
static const u16 sReelTimeWindow_Tilemap[];
|
|
static const u16 sEmptyTilemap[];
|
|
static void (*const sDigitalDisplaySceneExitCallbacks[])(void);
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeBolt;
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeNumberGap;
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeShadow;
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeNumbers;
|
|
static const struct SpriteTemplate sSpriteTemplate_BrokenReelTimeMachine;
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeMachineAntennae;
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeMachine;
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelBackground;
|
|
static const struct SpriteTemplate sSpriteTemplate_CoinNumber;
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelSymbol;
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimePikachu;
|
|
static const struct SubspriteTable sSubspriteTable_ReelTimeNumberGap[];
|
|
static const struct SubspriteTable sSubspriteTable_ReelTimeShadow[];
|
|
static const struct SubspriteTable sSubspriteTable_BrokenReelTimeMachine[];
|
|
static const struct SubspriteTable sSubspriteTable_ReelTimeMachineAntennae[];
|
|
static const struct SubspriteTable sSubspriteTable_ReelTimeMachine[];
|
|
static const struct SubspriteTable sSubspriteTable_ReelBackground[];
|
|
|
|
static const struct BgTemplate sBgTemplates[] =
|
|
{
|
|
{
|
|
.bg = 0,
|
|
.charBaseIndex = 2,
|
|
.mapBaseIndex = 31,
|
|
.screenSize = 0,
|
|
.paletteMode = 0,
|
|
.priority = 0,
|
|
.baseTile = 0
|
|
},
|
|
{
|
|
.bg = 1,
|
|
.charBaseIndex = 1,
|
|
.mapBaseIndex = 28,
|
|
.screenSize = 0,
|
|
.paletteMode = 0,
|
|
.priority = 1,
|
|
.baseTile = 0
|
|
},
|
|
{
|
|
.bg = 2,
|
|
.charBaseIndex = 1,
|
|
.mapBaseIndex = 29,
|
|
.screenSize = 0,
|
|
.paletteMode = 0,
|
|
.priority = 2,
|
|
.baseTile = 0
|
|
},
|
|
{
|
|
.bg = 3,
|
|
.charBaseIndex = 1,
|
|
.mapBaseIndex = 30,
|
|
.screenSize = 0,
|
|
.paletteMode = 0,
|
|
.priority = 1,
|
|
.baseTile = 0
|
|
},
|
|
};
|
|
|
|
static const struct WindowTemplate sWindowTemplates[] =
|
|
{
|
|
{
|
|
.bg = 0,
|
|
.tilemapLeft = 2,
|
|
.tilemapTop = 15,
|
|
.width = 27,
|
|
.height = 4,
|
|
.paletteNum = 15,
|
|
.baseBlock = 0x194
|
|
},
|
|
DUMMY_WIN_TEMPLATE
|
|
};
|
|
|
|
static const struct WindowTemplate sWindowTemplate_InfoBox =
|
|
{
|
|
.bg = 0,
|
|
.tilemapLeft = 1,
|
|
.tilemapTop = 3,
|
|
.width = 20,
|
|
.height = 13,
|
|
.paletteNum = 13,
|
|
.baseBlock = 1
|
|
};
|
|
|
|
static const u8 sColors_ReeltimeHelp[] = {TEXT_COLOR_LIGHT_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY};
|
|
|
|
static bool8 (*const sSlotTasks[])(struct Task *task) =
|
|
{
|
|
[SLOTTASK_UNFADE] = SlotTask_UnfadeScreen,
|
|
[SLOTTASK_WAIT_FADE] = SlotTask_WaitUnfade,
|
|
[SLOTTASK_READY_NEW_SPIN] = SlotTask_ReadyNewSpin,
|
|
[SLOTTASK_READY_NEW_RT_SPIN] = SlotTask_ReadyNewReelTimeSpin,
|
|
[SLOTTASK_ASK_INSERT_BET] = SlotTask_AskInsertBet,
|
|
[SLOTTASK_BET_INPUT] = SlotTask_HandleBetInput,
|
|
[SLOTTASK_MSG_NEED_3_COINS] = SlotTask_PrintMsg_Need3Coins,
|
|
[SLOTTASK_WAIT_MSG_NEED_3_COINS] = SlotTask_WaitMsg_Need3Coins,
|
|
[SLOTTASK_WAIT_INFO_BOX] = SlotTask_WaitInfoBox,
|
|
[SLOTTASK_START_SPIN] = SlotTask_StartSpin,
|
|
[SLOTTASK_START_RT_SPIN] = SlotTask_StartReelTimeSpin,
|
|
[SLOTTASK_RESET_BIAS_FAILURE] = SlotTask_ResetBiasFailure,
|
|
[SLOTTASK_WAIT_REEL_STOP] = SlotTask_WaitReelStop,
|
|
[SLOTTASK_WAIT_ALL_REELS_STOP] = SlotTask_WaitAllReelsStop,
|
|
[SLOTTASK_CHECK_MATCHES] = SlotTask_CheckMatches,
|
|
[SLOTTASK_WAIT_PAYOUT] = SlotTask_WaitPayout,
|
|
[SLOTTASK_END_PAYOUT] = SlotTask_EndPayout,
|
|
[SLOTTASK_MATCHED_POWER] = SlotTask_MatchedPower,
|
|
[SLOTTASK_WAIT_RT_ANIM] = SlotTask_WaitReelTimeAnim,
|
|
[SLOTTASK_RESET_BET_TILES] = SlotTask_ResetBetTiles,
|
|
[SLOTTASK_NO_MATCHES] = SlotTask_NoMatches,
|
|
[SLOTTASK_ASK_QUIT] = SlotTask_AskQuit,
|
|
[SLOTTASK_HANDLE_QUIT_INPUT] = SlotTask_HandleQuitInput,
|
|
[SLOTTASK_MSG_MAX_COINS] = SlotTask_PrintMsg_MaxCoins,
|
|
[SLOTTASK_WAIT_MSG_MAX_COINS] = SlotTask_WaitMsg_MaxCoins,
|
|
[SLOTTASK_MSG_NO_MORE_COINS] = SlotTask_PrintMsg_NoMoreCoins,
|
|
[SLOTTASK_WAIT_MSG_NO_MORE_COINS] = SlotTask_WaitMsg_NoMoreCoins,
|
|
[SLOTTASK_END] = SlotTask_EndGame,
|
|
[SLOTTASK_FREE] = SlotTask_FreeDataStructures,
|
|
};
|
|
|
|
static bool8 (*const sPayoutTasks[])(struct Task *task) =
|
|
{
|
|
[PAYOUT_TASK_INIT] = PayoutTask_Init,
|
|
[PAYOUT_TASK_GIVE_PAYOUT] = PayoutTask_GivePayout,
|
|
[PAYOUT_TASK_FREE] = PayoutTask_Free,
|
|
};
|
|
|
|
static bool8 (*const sReelTasks[])(struct Task *task) =
|
|
{
|
|
[REEL_TASK_STILL] = ReelTask_StayStill,
|
|
[REEL_TASK_SPIN] = ReelTask_Spin,
|
|
[REEL_TASK_DECIDE_STOP] = ReelTask_DecideStop,
|
|
[REEL_TASK_STOP_MOVE] = ReelTask_MoveToStop,
|
|
[REEL_TASK_STOP_SHAKE] = ReelTask_ShakingStop,
|
|
};
|
|
|
|
// Returns true if it is possible to match the bias symbol in the reel.
|
|
//
|
|
// Modifies the winnerRows and reelExtraTurns to indicate how to match the bias
|
|
// symbol.
|
|
static bool8 (*const sDecideStop_Bias[NUM_REELS])(void) =
|
|
{
|
|
DecideStop_Bias_Reel1,
|
|
DecideStop_Bias_Reel2,
|
|
DecideStop_Bias_Reel3,
|
|
};
|
|
|
|
// The player will always lose (barring a few rare circumstances that were not
|
|
// accounted for in implementation).
|
|
//
|
|
// Modifies the winnerRows and reelExtraTurns to indicate how to make the player
|
|
// lose.
|
|
static void (*const sDecideStop_NoBias[NUM_REELS])(void) =
|
|
{
|
|
DecideStop_NoBias_Reel1,
|
|
DecideStop_NoBias_Reel2,
|
|
DecideStop_NoBias_Reel3,
|
|
};
|
|
|
|
// The magnitude of the shock depends on how many extra turns are added.
|
|
static const u16 sReelStopShocks[] = {2, 4, 4, 4, 8};
|
|
|
|
static bool8 (*const sDecideStop_Bias_Reel1_Bets[MAX_BET])(u8 sym1, u8 sym2) =
|
|
{
|
|
DecideStop_Bias_Reel1_Bet1,
|
|
DecideStop_Bias_Reel1_Bet2or3,
|
|
DecideStop_Bias_Reel1_Bet2or3,
|
|
};
|
|
|
|
static bool8 (*const sDecideStop_Bias_Reel2_Bets[MAX_BET])(void) =
|
|
{
|
|
DecideStop_Bias_Reel2_Bet1or2,
|
|
DecideStop_Bias_Reel2_Bet1or2,
|
|
DecideStop_Bias_Reel2_Bet3,
|
|
};
|
|
|
|
static bool8 (*const sDecideStop_Bias_Reel3_Bets[MAX_BET])(u8 biasSymbol) =
|
|
{
|
|
DecideStop_Bias_Reel3_Bet1or2,
|
|
DecideStop_Bias_Reel3_Bet1or2,
|
|
DecideStop_Bias_Reel3_Bet3,
|
|
};
|
|
|
|
static void (*const sDecideStop_NoBias_Reel2_Bets[MAX_BET])(void) =
|
|
{
|
|
DecideStop_NoBias_Reel2_Bet1,
|
|
DecideStop_NoBias_Reel2_Bet2,
|
|
DecideStop_NoBias_Reel2_Bet3,
|
|
};
|
|
|
|
static void (*const sDecideStop_NoBias_Reel3_Bets[MAX_BET])(void) =
|
|
{
|
|
DecideStop_NoBias_Reel3_Bet1,
|
|
DecideStop_NoBias_Reel3_Bet2,
|
|
DecideStop_NoBias_Reel3_Bet3,
|
|
};
|
|
|
|
static void (*const sReelStopButtonTasks[])(struct Task *task, u8 taskId) =
|
|
{
|
|
StopReelButton_Press,
|
|
StopReelButton_Wait,
|
|
StopReelButton_Unpress,
|
|
};
|
|
|
|
static const s16 sReelButtonOffsets[NUM_REELS] = {5, 10, 15};
|
|
|
|
static void (*const sPikaPowerBoltTasks[])(struct Task *task) =
|
|
{
|
|
PikaPowerBolt_Idle,
|
|
PikaPowerBolt_AddBolt,
|
|
PikaPowerBolt_WaitAnim,
|
|
PikaPowerBolt_ClearAll,
|
|
};
|
|
|
|
static const u16 sPikaPowerTileTable[][2] =
|
|
{
|
|
{0x9e, 0x6e},
|
|
{0x9f, 0x6f},
|
|
{0xaf, 0x7f},
|
|
};
|
|
|
|
static void (*const sReelTimeTasks[])(struct Task *task) =
|
|
{
|
|
[RT_TASK_INIT] = ReelTime_Init,
|
|
[RT_TASK_WINDOW_ENTER] = ReelTime_WindowEnter,
|
|
[RT_TASK_WAIT_START_PIKA] = ReelTime_WaitStartPikachu,
|
|
[RT_TASK_PIKA_SPEEDUP1] = ReelTime_PikachuSpeedUp1,
|
|
[RT_TASK_PIKA_SPEEDUP2] = ReelTime_PikachuSpeedUp2,
|
|
[RT_TASK_WAIT_REEL] = ReelTime_WaitReel,
|
|
[RT_TASK_CHECK_EXPLODE] = ReelTime_CheckExplode,
|
|
[RT_TASK_LAND] = ReelTime_LandOnOutcome,
|
|
[RT_TASK_PIKA_REACT] = ReelTime_PikachuReact,
|
|
[RT_TASK_WAIT_CLEAR_POWER] = ReelTime_WaitClearPikaPower,
|
|
[RT_TASK_CLOSE_WINDOW_SUCCESS] = ReelTime_CloseWindow,
|
|
[RT_TASK_DESTROY_SPRITES] = ReelTime_DestroySprites,
|
|
[RT_TASK_SET_REEL_SPEED] = ReelTime_SetReelSpeed,
|
|
[RT_TASK_END_SUCCESS] = ReelTime_EndSuccess,
|
|
[RT_TASK_EXPLODE] = ReelTime_ExplodeMachine,
|
|
[RT_TASK_WAIT_EXPLODE] = ReelTime_WaitExplode,
|
|
[RT_TASK_WAIT_SMOKE] = ReelTime_WaitSmoke,
|
|
[RT_TASK_CLOSE_WINDOW_FAILURE] = ReelTime_CloseWindow,
|
|
[RT_TASK_END_FAILURE] = ReelTime_EndFailure,
|
|
};
|
|
|
|
static const u8 sReelTimePikachuAnimIds[] = {1, 1, 2, 2};
|
|
static const s16 sReelTimeBoltDelays[] = {64, 48, 24, 8};
|
|
static const s16 sPikachuAuraFlashDelays[] = {10, 8, 6, 4};
|
|
|
|
static void (*const sInfoBoxTasks[])(struct Task *task) =
|
|
{
|
|
// Go to Info screen
|
|
InfoBox_FadeIn,
|
|
InfoBox_WaitFade,
|
|
InfoBox_DrawWindow,
|
|
InfoBox_WaitFade,
|
|
InfoBox_AddText,
|
|
InfoBox_WaitFade,
|
|
// On Info screen
|
|
InfoBox_WaitInput,
|
|
// Exit Info screen
|
|
InfoBox_WaitFade,
|
|
InfoBox_LoadSlotMachineTilemap,
|
|
InfoBox_WaitFade,
|
|
InfoBox_CreateDigitalDisplay,
|
|
InfoBox_WaitFade,
|
|
InfoBox_LoadPikaPowerMeter,
|
|
InfoBox_WaitFade,
|
|
InfoBox_FreeTask,
|
|
};
|
|
|
|
// Just idles, digital display is handled by CreateDigitalDisplayScene and sprite callbacks
|
|
static void (*const sDigitalDisplayTasks[])(struct Task *task) =
|
|
{
|
|
DigitalDisplay_Idle,
|
|
};
|
|
|
|
#define tState data[0]
|
|
|
|
static void Task_FadeToSlotMachine(u8 taskId)
|
|
{
|
|
switch (gTasks[taskId].tState)
|
|
{
|
|
case 0:
|
|
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK);
|
|
gTasks[taskId].tState++;
|
|
break;
|
|
case 1:
|
|
if (!gPaletteFade.active)
|
|
{
|
|
SetMainCallback2(CB2_SlotMachineSetup);
|
|
DestroyTask(taskId);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void PlaySlotMachine(u8 machineId, MainCallback exitCallback)
|
|
{
|
|
u8 taskId;
|
|
|
|
sSlotMachine = AllocZeroed(sizeof(*sSlotMachine));
|
|
PlaySlotMachine_Internal(machineId, exitCallback);
|
|
taskId = CreateTask(Task_FadeToSlotMachine, 0);
|
|
gTasks[taskId].tState = 0;
|
|
}
|
|
|
|
#undef tState
|
|
|
|
static void CB2_SlotMachineSetup(void)
|
|
{
|
|
switch (gMain.state)
|
|
{
|
|
case 0:
|
|
SlotMachineSetup_InitBgsWindows();
|
|
InitSlotMachine();
|
|
gMain.state++;
|
|
break;
|
|
case 1:
|
|
SlotMachineSetup_InitVRAM();
|
|
gMain.state++;
|
|
break;
|
|
case 2:
|
|
SlotMachineSetup_InitOAM();
|
|
SlotMachineSetup_InitGpuRegs();
|
|
gMain.state++;
|
|
break;
|
|
case 3:
|
|
SlotMachineSetup_InitPalsSpritesTasks();
|
|
gMain.state++;
|
|
break;
|
|
case 4:
|
|
SlotMachineSetup_InitTilemaps();
|
|
gMain.state++;
|
|
break;
|
|
case 5:
|
|
SlotMachineSetup_LoadGfxAndTilemaps();
|
|
gMain.state++;
|
|
break;
|
|
case 6:
|
|
SlotMachineSetup_InitVBlank();
|
|
gMain.state++;
|
|
break;
|
|
case 7:
|
|
BeginNormalPaletteFade(-1, 0, 0x10, 0, RGB_BLACK);
|
|
ShowBg(0);
|
|
ShowBg(1);
|
|
ShowBg(2);
|
|
ShowBg(3);
|
|
gMain.state++;
|
|
break;
|
|
case 8:
|
|
AllocDigitalDisplayGfx();
|
|
gMain.state++;
|
|
break;
|
|
case 9:
|
|
SetDigitalDisplayImagePtrs();
|
|
gMain.state++;
|
|
break;
|
|
case 10:
|
|
CreateSlotMachineSprites();
|
|
CreateGameplayTasks();
|
|
gMain.state++;
|
|
break;
|
|
case 11:
|
|
SetMainCallback2(CB2_SlotMachine);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void CB2_SlotMachine(void)
|
|
{
|
|
RunTasks();
|
|
AnimateSprites();
|
|
BuildOamBuffer();
|
|
UpdatePaletteFade();
|
|
}
|
|
|
|
static void SlotMachine_VBlankCB(void)
|
|
{
|
|
LoadOam();
|
|
ProcessSpriteCopyRequests();
|
|
TransferPlttBuffer();
|
|
SetGpuReg(REG_OFFSET_WIN0H, sSlotMachine->win0h);
|
|
SetGpuReg(REG_OFFSET_WIN0V, sSlotMachine->win0v);
|
|
SetGpuReg(REG_OFFSET_WININ, sSlotMachine->winIn);
|
|
SetGpuReg(REG_OFFSET_WINOUT, sSlotMachine->winOut);
|
|
}
|
|
|
|
#define tMachineId data[0]
|
|
#define tExitCallback data[1]
|
|
|
|
static void PlaySlotMachine_Internal(u8 machineId, MainCallback exitCallback)
|
|
{
|
|
struct Task *task = &gTasks[CreateTask(SlotMachineDummyTask, 0xFF)];
|
|
task->tMachineId = machineId;
|
|
StoreWordInTwoHalfwords(&task->tExitCallback, (intptr_t)exitCallback);
|
|
}
|
|
|
|
// Extracts and assigns machineId and exit callback from task.
|
|
static void SlotMachine_InitFromTask(void)
|
|
{
|
|
struct Task *task = &gTasks[FindTaskIdByFunc(SlotMachineDummyTask)];
|
|
sSlotMachine->machineId = task->tMachineId;
|
|
LoadWordFromTwoHalfwords((u16 *)&task->tExitCallback, (u32 *)&sSlotMachine->prevMainCb);
|
|
}
|
|
|
|
static void SlotMachineDummyTask(u8 taskId)
|
|
{
|
|
}
|
|
|
|
#undef tMachineId
|
|
#undef tExitCallback
|
|
|
|
static void SlotMachineSetup_InitBgsWindows(void)
|
|
{
|
|
SetVBlankCallback(NULL);
|
|
SetHBlankCallback(NULL);
|
|
CpuFill32(0, (void *)VRAM, VRAM_SIZE);
|
|
ResetBgsAndClearDma3BusyFlags(0);
|
|
InitBgsFromTemplates(0, sBgTemplates, ARRAY_COUNT(sBgTemplates));
|
|
InitWindows(sWindowTemplates);
|
|
DeactivateAllTextPrinters();
|
|
}
|
|
|
|
static void SlotMachineSetup_InitVBlank(void)
|
|
{
|
|
SetVBlankCallback(SlotMachine_VBlankCB);
|
|
EnableInterrupts(INTR_FLAG_VBLANK);
|
|
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON | DISPCNT_WIN0_ON);
|
|
}
|
|
|
|
static void SlotMachineSetup_InitVRAM(void)
|
|
{
|
|
DmaClearLarge16(3, (u16 *)(BG_VRAM), BG_VRAM_SIZE, 0x1000);
|
|
}
|
|
|
|
static void SlotMachineSetup_InitOAM(void)
|
|
{
|
|
DmaClear16(3, (u16 *)OAM, OAM_SIZE);
|
|
}
|
|
|
|
static void SlotMachineSetup_InitGpuRegs(void)
|
|
{
|
|
SetGpuReg(REG_OFFSET_BG0CNT, 0);
|
|
SetGpuReg(REG_OFFSET_BG1CNT, 0);
|
|
SetGpuReg(REG_OFFSET_BG2CNT, 0);
|
|
SetGpuReg(REG_OFFSET_BG3CNT, 0);
|
|
SetGpuReg(REG_OFFSET_BG0HOFS, 0);
|
|
SetGpuReg(REG_OFFSET_BG0VOFS, 0);
|
|
SetGpuReg(REG_OFFSET_BG1HOFS, 0);
|
|
SetGpuReg(REG_OFFSET_BG1VOFS, 0);
|
|
SetGpuReg(REG_OFFSET_BG2HOFS, 0);
|
|
SetGpuReg(REG_OFFSET_BG2VOFS, 0);
|
|
SetGpuReg(REG_OFFSET_BG3HOFS, 0);
|
|
SetGpuReg(REG_OFFSET_BG3VOFS, 0);
|
|
SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR);
|
|
SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR);
|
|
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG3 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_OBJ);
|
|
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(9, 8));
|
|
}
|
|
|
|
// Set up initial state of slot machine
|
|
static void InitSlotMachine(void)
|
|
{
|
|
u8 i;
|
|
|
|
SlotMachine_InitFromTask();
|
|
sSlotMachine->state = SLOTTASK_UNFADE;
|
|
sSlotMachine->pikaPowerBolts = 0;
|
|
sSlotMachine->luckyGame = Random() & 1;
|
|
sSlotMachine->machineBias = 0;
|
|
sSlotMachine->matches = 0;
|
|
sSlotMachine->reelTimeSpinsLeft = 0;
|
|
sSlotMachine->reelTimeSpinsUsed = 0;
|
|
sSlotMachine->coins = GetCoins();
|
|
sSlotMachine->payout = 0;
|
|
sSlotMachine->netCoinLoss = 0;
|
|
sSlotMachine->bet = 0;
|
|
sSlotMachine->currentReel = LEFT_REEL;
|
|
sSlotMachine->reelSpeed = REEL_NORMAL_SPEED;
|
|
sSlotMachine->win0h = DISPLAY_WIDTH;
|
|
sSlotMachine->win0v = DISPLAY_HEIGHT;
|
|
sSlotMachine->winIn = WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR;
|
|
sSlotMachine->winOut = WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR;
|
|
sSlotMachine->backupMapMusic = GetCurrentMapMusic();
|
|
|
|
for (i = 0; i < NUM_REELS; i++)
|
|
{
|
|
sSlotMachine->reelShockOffsets[i] = 0;
|
|
sSlotMachine->reelPositions[i] = sInitialReelPositions[i][sSlotMachine->luckyGame] % SYMBOLS_PER_REEL;
|
|
sSlotMachine->reelPixelOffsets[i] = REEL_HEIGHT - sSlotMachine->reelPositions[i] * REEL_SYMBOL_HEIGHT;
|
|
sSlotMachine->reelPixelOffsets[i] %= REEL_HEIGHT;
|
|
}
|
|
AlertTVThatPlayerPlayedSlotMachine(GetCoins());
|
|
}
|
|
|
|
static void SlotMachineSetup_InitPalsSpritesTasks(void)
|
|
{
|
|
ResetPaletteFade();
|
|
ResetSpriteData();
|
|
gOamLimit = 0x80;
|
|
FreeAllSpritePalettes();
|
|
ResetTasks();
|
|
}
|
|
|
|
static void SlotMachineSetup_InitTilemaps(void)
|
|
{
|
|
sSelectedPikaPowerTile = Alloc(8);
|
|
sReelOverlay_Tilemap = AllocZeroed(14);
|
|
sReelButtonPress_Tilemap = AllocZeroed(8);
|
|
|
|
// several of these are 1 bit off from each other
|
|
sReelOverlay_Tilemap[0] = 0x2051;
|
|
sReelOverlay_Tilemap[1] = 0x2851;
|
|
sReelOverlay_Tilemap[2] = 0x2061;
|
|
sReelOverlay_Tilemap[3] = 0x2861;
|
|
sReelOverlay_Tilemap[4] = 0x20BE;
|
|
sReelOverlay_Tilemap[5] = 0x28BE;
|
|
sReelOverlay_Tilemap[6] = 0x20BF;
|
|
}
|
|
|
|
static void SlotMachineSetup_LoadGfxAndTilemaps(void)
|
|
{
|
|
LoadMenuGfx();
|
|
LoadMenuAndReelOverlayTilemaps();
|
|
LoadSlotMachineGfx();
|
|
LoadMessageBoxGfx(0, 0x200, BG_PLTT_ID(15));
|
|
LoadUserWindowBorderGfx(0, 0x214, BG_PLTT_ID(14));
|
|
PutWindowTilemap(0);
|
|
}
|
|
|
|
static void CreateSlotMachineSprites(void)
|
|
{
|
|
CreateReelSymbolSprites();
|
|
CreateCreditPayoutNumberSprites();
|
|
CreateInvisibleFlashMatchLineSprites();
|
|
CreateReelBackgroundSprite();
|
|
}
|
|
|
|
static void CreateGameplayTasks(void)
|
|
{
|
|
CreatePikaPowerBoltTask();
|
|
CreateReelTasks();
|
|
CreateDigitalDisplayTask();
|
|
CreateSlotMachineTasks();
|
|
}
|
|
|
|
static void CreateSlotMachineTasks(void)
|
|
{
|
|
Task_SlotMachine(CreateTask(Task_SlotMachine, 0));
|
|
}
|
|
|
|
static void Task_SlotMachine(u8 taskId)
|
|
{
|
|
while (sSlotTasks[sSlotMachine->state](&gTasks[taskId]))
|
|
;
|
|
}
|
|
|
|
#define tTimer data[0]
|
|
#define tTimer2 data[1]
|
|
|
|
// SLOTTASK_UNFADE
|
|
static bool8 SlotTask_UnfadeScreen(struct Task *task)
|
|
{
|
|
BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB(0, 0, 0));
|
|
LoadPikaPowerMeter(sSlotMachine->pikaPowerBolts);
|
|
sSlotMachine->state++; // SLOTTASK_WAIT_FADE
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_WAIT_FADE
|
|
static bool8 SlotTask_WaitUnfade(struct Task *task)
|
|
{
|
|
if (!gPaletteFade.active)
|
|
sSlotMachine->state++;
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_READY_NEW_SPIN
|
|
static bool8 SlotTask_ReadyNewSpin(struct Task *task)
|
|
{
|
|
sSlotMachine->payout = 0;
|
|
sSlotMachine->bet = 0;
|
|
sSlotMachine->currentReel = LEFT_REEL;
|
|
sSlotMachine->machineBias &= (BIAS_STRAIGHT_7 | BIAS_MIXED_7);
|
|
sSlotMachine->state = SLOTTASK_ASK_INSERT_BET;
|
|
if (sSlotMachine->coins <= 0)
|
|
{
|
|
sSlotMachine->state = SLOTTASK_MSG_NO_MORE_COINS;
|
|
}
|
|
else if (sSlotMachine->reelTimeSpinsLeft)
|
|
{
|
|
sSlotMachine->state = SLOTTASK_READY_NEW_RT_SPIN;
|
|
CreateDigitalDisplayScene(DIG_DISPLAY_REEL_TIME);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// SLOTTASK_READY_NEW_RT_SPIN
|
|
static bool8 SlotTask_ReadyNewReelTimeSpin(struct Task *task)
|
|
{
|
|
if (IsDigitalDisplayAnimFinished())
|
|
sSlotMachine->state = SLOTTASK_ASK_INSERT_BET;
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_ASK_INSERT_BET
|
|
static bool8 SlotTask_AskInsertBet(struct Task *task)
|
|
{
|
|
CreateDigitalDisplayScene(DIG_DISPLAY_INSERT_BET);
|
|
sSlotMachine->state = SLOTTASK_BET_INPUT;
|
|
if (sSlotMachine->coins >= MAX_COINS)
|
|
sSlotMachine->state = SLOTTASK_MSG_MAX_COINS;
|
|
return TRUE;
|
|
}
|
|
|
|
// SLOTTASK_BET_INPUT
|
|
static bool8 SlotTask_HandleBetInput(struct Task *task)
|
|
{
|
|
s16 i;
|
|
|
|
if (JOY_NEW(SELECT_BUTTON))
|
|
{
|
|
OpenInfoBox(DIG_DISPLAY_INSERT_BET);
|
|
sSlotMachine->state = SLOTTASK_WAIT_INFO_BOX;
|
|
}
|
|
// Try to bet the max amount
|
|
else if (JOY_NEW(R_BUTTON))
|
|
{
|
|
if (sSlotMachine->coins - (MAX_BET - sSlotMachine->bet) >= 0)
|
|
{
|
|
for (i = sSlotMachine->bet; i < MAX_BET; i++)
|
|
LightenBetTiles(i);
|
|
sSlotMachine->coins -= (MAX_BET - sSlotMachine->bet);
|
|
sSlotMachine->bet = MAX_BET;
|
|
sSlotMachine->state = SLOTTASK_START_SPIN;
|
|
PlaySE(SE_SHOP);
|
|
}
|
|
// Not enough coins
|
|
else
|
|
{
|
|
sSlotMachine->state = SLOTTASK_MSG_NEED_3_COINS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Increase bet
|
|
if (JOY_NEW(DPAD_DOWN) && sSlotMachine->coins != 0)
|
|
{
|
|
PlaySE(SE_SHOP);
|
|
LightenBetTiles(sSlotMachine->bet);
|
|
sSlotMachine->coins--;
|
|
sSlotMachine->bet++;
|
|
}
|
|
|
|
// Maxed bet or finished betting
|
|
if (sSlotMachine->bet >= MAX_BET || (sSlotMachine->bet != 0 && JOY_NEW(A_BUTTON)))
|
|
sSlotMachine->state = SLOTTASK_START_SPIN;
|
|
|
|
// Quit prompt
|
|
if (JOY_NEW(B_BUTTON))
|
|
sSlotMachine->state = SLOTTASK_ASK_QUIT;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_MSG_NEED_3_COINS
|
|
static bool8 SlotTask_PrintMsg_Need3Coins(struct Task *task)
|
|
{
|
|
DrawDialogueFrame(0, FALSE);
|
|
AddTextPrinterParameterized(0, FONT_NORMAL, gText_YouDontHaveThreeCoins, 0, 1, 0, 0);
|
|
CopyWindowToVram(0, COPYWIN_FULL);
|
|
sSlotMachine->state = SLOTTASK_WAIT_MSG_NEED_3_COINS;
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_WAIT_MSG_NEED_3_COINS
|
|
static bool8 SlotTask_WaitMsg_Need3Coins(struct Task *task)
|
|
{
|
|
if (JOY_NEW(A_BUTTON | B_BUTTON))
|
|
{
|
|
ClearDialogWindowAndFrame(0, TRUE);
|
|
sSlotMachine->state = SLOTTASK_BET_INPUT;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_WAIT_INFO_BOX
|
|
static bool8 SlotTask_WaitInfoBox(struct Task *task)
|
|
{
|
|
if (IsInfoBoxClosed())
|
|
sSlotMachine->state = SLOTTASK_BET_INPUT;
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_START_SPIN
|
|
static bool8 SlotTask_StartSpin(struct Task *task)
|
|
{
|
|
DrawMachineBias();
|
|
DestroyDigitalDisplayScene();
|
|
|
|
SpinSlotReel(LEFT_REEL);
|
|
SpinSlotReel(MIDDLE_REEL);
|
|
SpinSlotReel(RIGHT_REEL);
|
|
|
|
IncrementDailySlotsUses();
|
|
|
|
task->tTimer = 0;
|
|
if (sSlotMachine->machineBias & BIAS_REELTIME)
|
|
{
|
|
BeginReelTime();
|
|
sSlotMachine->state = SLOTTASK_START_RT_SPIN;
|
|
}
|
|
else
|
|
{
|
|
CreateDigitalDisplayScene(DIG_DISPLAY_STOP_REEL);
|
|
sSlotMachine->state = SLOTTASK_RESET_BIAS_FAILURE;
|
|
}
|
|
sSlotMachine->reelSpeed = REEL_NORMAL_SPEED;
|
|
if (sSlotMachine->reelTimeSpinsLeft)
|
|
sSlotMachine->reelSpeed = ReelTimeSpeed();
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_START_RT_SPIN
|
|
static bool8 SlotTask_StartReelTimeSpin(struct Task *task)
|
|
{
|
|
if (IsReelTimeTaskDone())
|
|
{
|
|
CreateDigitalDisplayScene(DIG_DISPLAY_STOP_REEL);
|
|
sSlotMachine->machineBias &= ~BIAS_REELTIME;
|
|
sSlotMachine->state = SLOTTASK_RESET_BIAS_FAILURE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_RESET_BIAS_FAILURE
|
|
static bool8 SlotTask_ResetBiasFailure(struct Task *task)
|
|
{
|
|
if (++task->tTimer >= 30)
|
|
{
|
|
ResetBiasFailure();
|
|
sSlotMachine->state = SLOTTASK_WAIT_REEL_STOP;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_WAIT_REEL_STOP
|
|
static bool8 SlotTask_WaitReelStop(struct Task *task)
|
|
{
|
|
if (JOY_NEW(A_BUTTON))
|
|
{
|
|
PlaySE(SE_CONTEST_PLACE);
|
|
StopSlotReel(sSlotMachine->currentReel);
|
|
PressStopReelButton(sSlotMachine->currentReel);
|
|
sSlotMachine->state = SLOTTASK_WAIT_ALL_REELS_STOP;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_WAIT_ALL_REELS_STOP
|
|
static bool8 SlotTask_WaitAllReelsStop(struct Task *task)
|
|
{
|
|
if (!IsSlotReelMoving(sSlotMachine->currentReel))
|
|
{
|
|
sSlotMachine->currentReel++;
|
|
sSlotMachine->state = SLOTTASK_WAIT_REEL_STOP;
|
|
if (sSlotMachine->currentReel >= NUM_REELS)
|
|
{
|
|
sSlotMachine->state = SLOTTASK_CHECK_MATCHES;
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_CHECK_MATCHES
|
|
static bool8 SlotTask_CheckMatches(struct Task *task)
|
|
{
|
|
sSlotMachine->machineBias &= (BIAS_STRAIGHT_7 | BIAS_MIXED_7);
|
|
CheckMatch();
|
|
if (sSlotMachine->reelTimeSpinsLeft)
|
|
{
|
|
sSlotMachine->reelTimeSpinsLeft--;
|
|
sSlotMachine->reelTimeSpinsUsed++;
|
|
}
|
|
|
|
if (sSlotMachine->matches)
|
|
{
|
|
sSlotMachine->state = SLOTTASK_WAIT_PAYOUT;
|
|
AwardPayout();
|
|
FlashSlotMachineLights();
|
|
if ((sSlotMachine->netCoinLoss -= sSlotMachine->payout) < 0)
|
|
{
|
|
sSlotMachine->netCoinLoss = 0;
|
|
}
|
|
if (sSlotMachine->matches & ((1 << MATCH_BLUE_7) | (1 << MATCH_RED_7)))
|
|
{
|
|
PlayFanfare(MUS_SLOTS_JACKPOT);
|
|
CreateDigitalDisplayScene(DIG_DISPLAY_BONUS_BIG);
|
|
}
|
|
else if (sSlotMachine->matches & (1 << MATCH_MIXED_7))
|
|
{
|
|
PlayFanfare(MUS_SLOTS_JACKPOT);
|
|
CreateDigitalDisplayScene(DIG_DISPLAY_BONUS_REG);
|
|
}
|
|
else
|
|
{
|
|
PlayFanfare(MUS_SLOTS_WIN);
|
|
CreateDigitalDisplayScene(DIG_DISPLAY_WIN);
|
|
}
|
|
|
|
if (sSlotMachine->matches & ((1 << MATCH_MIXED_7) | (1 << MATCH_BLUE_7) | (1 << MATCH_RED_7)))
|
|
{
|
|
sSlotMachine->machineBias &= ~(BIAS_STRAIGHT_7 | BIAS_MIXED_7);
|
|
if (sSlotMachine->matches & ((1 << MATCH_BLUE_7) | (1 << MATCH_RED_7)))
|
|
{
|
|
// ReelTime ends if it was ongoing
|
|
sSlotMachine->reelTimeSpinsLeft = 0;
|
|
sSlotMachine->reelTimeSpinsUsed = 0;
|
|
sSlotMachine->luckyGame = FALSE;
|
|
if (sSlotMachine->matches & (1 << MATCH_BLUE_7))
|
|
sSlotMachine->luckyGame = TRUE;
|
|
}
|
|
}
|
|
if (sSlotMachine->matches & (1 << MATCH_POWER) && sSlotMachine->pikaPowerBolts < 16)
|
|
{
|
|
sSlotMachine->pikaPowerBolts++;
|
|
AddPikaPowerBolt(sSlotMachine->pikaPowerBolts);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CreateDigitalDisplayScene(DIG_DISPLAY_LOSE);
|
|
sSlotMachine->state = SLOTTASK_NO_MATCHES;
|
|
if ((sSlotMachine->netCoinLoss += sSlotMachine->bet) > MAX_COINS)
|
|
sSlotMachine->netCoinLoss = MAX_COINS;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_WAIT_PAYOUT
|
|
static bool8 SlotTask_WaitPayout(struct Task *task)
|
|
{
|
|
if (IsFinalTask_Task_Payout())
|
|
sSlotMachine->state = SLOTTASK_END_PAYOUT;
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_END_PAYOUT
|
|
static bool8 SlotTask_EndPayout(struct Task *task)
|
|
{
|
|
if (TryStopSlotMachineLights())
|
|
{
|
|
sSlotMachine->state = SLOTTASK_RESET_BET_TILES;
|
|
|
|
if (sSlotMachine->matches & ((1 << MATCH_RED_7) | (1 << MATCH_BLUE_7)))
|
|
IncrementGameStat(GAME_STAT_SLOT_JACKPOTS);
|
|
|
|
if (sSlotMachine->matches & (1 << MATCH_REPLAY))
|
|
{
|
|
sSlotMachine->currentReel = LEFT_REEL;
|
|
sSlotMachine->state = SLOTTASK_START_SPIN;
|
|
}
|
|
|
|
if (sSlotMachine->matches & (1 << MATCH_POWER))
|
|
sSlotMachine->state = SLOTTASK_MATCHED_POWER;
|
|
|
|
if (sSlotMachine->reelTimeSpinsLeft && sSlotMachine->matches & (1 << MATCH_REPLAY))
|
|
{
|
|
CreateDigitalDisplayScene(DIG_DISPLAY_REEL_TIME);
|
|
sSlotMachine->state = SLOTTASK_WAIT_RT_ANIM;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_MATCHED_POWER
|
|
static bool8 SlotTask_MatchedPower(struct Task *task)
|
|
{
|
|
if (!IsPikaPowerBoltAnimating())
|
|
{
|
|
sSlotMachine->state = SLOTTASK_RESET_BET_TILES;
|
|
if (sSlotMachine->matches & (1 << MATCH_REPLAY))
|
|
{
|
|
sSlotMachine->state = SLOTTASK_START_SPIN;
|
|
if (sSlotMachine->reelTimeSpinsLeft)
|
|
{
|
|
CreateDigitalDisplayScene(DIG_DISPLAY_REEL_TIME);
|
|
sSlotMachine->state = SLOTTASK_WAIT_RT_ANIM;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_WAIT_RT_ANIM
|
|
static bool8 SlotTask_WaitReelTimeAnim(struct Task *task)
|
|
{
|
|
if (IsDigitalDisplayAnimFinished())
|
|
{
|
|
sSlotMachine->state = SLOTTASK_RESET_BET_TILES;
|
|
if (sSlotMachine->matches & (1 << MATCH_REPLAY))
|
|
{
|
|
sSlotMachine->state = SLOTTASK_START_SPIN;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_RESET_BET_TILES
|
|
static bool8 SlotTask_ResetBetTiles(struct Task *task)
|
|
{
|
|
DarkenBetTiles(0);
|
|
DarkenBetTiles(1);
|
|
DarkenBetTiles(2);
|
|
sSlotMachine->state = SLOTTASK_READY_NEW_SPIN;
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_NO_MATCHES
|
|
static bool8 SlotTask_NoMatches(struct Task *task)
|
|
{
|
|
if (++task->tTimer2 > 64)
|
|
{
|
|
task->tTimer2 = 0;
|
|
sSlotMachine->state = SLOTTASK_RESET_BET_TILES;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_ASK_QUIT
|
|
static bool8 SlotTask_AskQuit(struct Task *task)
|
|
{
|
|
DrawDialogueFrame(0, FALSE);
|
|
AddTextPrinterParameterized(0, FONT_NORMAL, gText_QuitTheGame, 0, 1, 0, 0);
|
|
CopyWindowToVram(0, COPYWIN_FULL);
|
|
CreateYesNoMenuParameterized(0x15, 7, 0x214, 0x180, 0xE, 0xF);
|
|
sSlotMachine->state = SLOTTASK_HANDLE_QUIT_INPUT;
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_HANDLE_QUIT_INPUT
|
|
static bool8 SlotTask_HandleQuitInput(struct Task *task)
|
|
{
|
|
s8 input = Menu_ProcessInputNoWrapClearOnChoose();
|
|
if (input == 0) // Chose to quit
|
|
{
|
|
ClearDialogWindowAndFrame(0, TRUE);
|
|
DarkenBetTiles(0);
|
|
DarkenBetTiles(1);
|
|
DarkenBetTiles(2);
|
|
sSlotMachine->coins += sSlotMachine->bet;
|
|
sSlotMachine->state = SLOTTASK_END;
|
|
}
|
|
else if (input == 1 || input == -1) // Chose not to quit
|
|
{
|
|
ClearDialogWindowAndFrame(0, TRUE);
|
|
sSlotMachine->state = SLOTTASK_BET_INPUT;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_MSG_MAX_COINS
|
|
static bool8 SlotTask_PrintMsg_MaxCoins(struct Task *task)
|
|
{
|
|
DrawDialogueFrame(0, FALSE);
|
|
AddTextPrinterParameterized(0, FONT_NORMAL, gText_YouveGot9999Coins, 0, 1, 0, 0);
|
|
CopyWindowToVram(0, COPYWIN_FULL);
|
|
sSlotMachine->state = SLOTTASK_WAIT_MSG_MAX_COINS;
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_WAIT_MSG_MAX_COINS
|
|
static bool8 SlotTask_WaitMsg_MaxCoins(struct Task *task)
|
|
{
|
|
if (JOY_NEW(A_BUTTON | B_BUTTON))
|
|
{
|
|
ClearDialogWindowAndFrame(0, TRUE);
|
|
sSlotMachine->state = SLOTTASK_BET_INPUT;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_MSG_NO_MORE_COINS
|
|
static bool8 SlotTask_PrintMsg_NoMoreCoins(struct Task *task)
|
|
{
|
|
DrawDialogueFrame(0, FALSE);
|
|
AddTextPrinterParameterized(0, FONT_NORMAL, gText_YouveRunOutOfCoins, 0, 1, 0, 0);
|
|
CopyWindowToVram(0, COPYWIN_FULL);
|
|
sSlotMachine->state = SLOTTASK_WAIT_MSG_NO_MORE_COINS;
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_WAIT_MSG_NO_MORE_COINS
|
|
static bool8 SlotTask_WaitMsg_NoMoreCoins(struct Task *task)
|
|
{
|
|
if (JOY_NEW(A_BUTTON | B_BUTTON))
|
|
{
|
|
ClearDialogWindowAndFrame(0, TRUE);
|
|
sSlotMachine->state = SLOTTASK_END;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_END
|
|
static bool8 SlotTask_EndGame(struct Task *task)
|
|
{
|
|
SetCoins(sSlotMachine->coins);
|
|
TryPutFindThatGamerOnAir(GetCoins());
|
|
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB(0, 0, 0));
|
|
sSlotMachine->state++; // SLOTTASK_FREE
|
|
return FALSE;
|
|
}
|
|
|
|
// SLOTTASK_FREE
|
|
static bool8 SlotTask_FreeDataStructures(struct Task *task)
|
|
{
|
|
if (!gPaletteFade.active)
|
|
{
|
|
SetMainCallback2(sSlotMachine->prevMainCb);
|
|
FREE_AND_SET_NULL(sImageTable_DigitalDisplay_Reel);
|
|
FREE_AND_SET_NULL(sImageTable_DigitalDisplay_Time);
|
|
FREE_AND_SET_NULL(sImageTable_DigitalDisplay_Insert);
|
|
FREE_AND_SET_NULL(sImageTable_DigitalDisplay_Stop);
|
|
FREE_AND_SET_NULL(sImageTable_DigitalDisplay_Win);
|
|
FREE_AND_SET_NULL(sImageTable_DigitalDisplay_Lose);
|
|
FREE_AND_SET_NULL(sImageTable_DigitalDisplay_Bonus);
|
|
FREE_AND_SET_NULL(sImageTable_DigitalDisplay_Big);
|
|
FREE_AND_SET_NULL(sImageTable_DigitalDisplay_Reg);
|
|
FREE_AND_SET_NULL(sImageTable_DigitalDisplay_AButton);
|
|
FREE_AND_SET_NULL(sImageTable_DigitalDisplay_Smoke);
|
|
FREE_AND_SET_NULL(sImageTable_DigitalDisplay_Number);
|
|
FREE_AND_SET_NULL(sImageTable_DigitalDisplay_Pokeball);
|
|
FREE_AND_SET_NULL(sImageTable_DigitalDisplay_DPad);
|
|
TRY_FREE_AND_SET_NULL(sImageTable_ReelTimePikachu);
|
|
TRY_FREE_AND_SET_NULL(sImageTable_ReelTimeMachineAntennae);
|
|
TRY_FREE_AND_SET_NULL(sImageTable_ReelTimeMachine);
|
|
TRY_FREE_AND_SET_NULL(sImageTable_BrokenReelTimeMachine);
|
|
FREE_AND_SET_NULL(sMenuGfx);
|
|
FREE_AND_SET_NULL(sSelectedPikaPowerTile);
|
|
FREE_AND_SET_NULL(sReelOverlay_Tilemap);
|
|
FREE_AND_SET_NULL(sDigitalDisplayGfxPtr);
|
|
FREE_AND_SET_NULL(sReelTimeGfxPtr);
|
|
FREE_AND_SET_NULL(sReelButtonPress_Tilemap);
|
|
FREE_AND_SET_NULL(sReelBackground_Gfx);
|
|
FREE_AND_SET_NULL(sReelBackgroundSpriteSheet);
|
|
FREE_AND_SET_NULL(sSlotMachineSpritesheetsPtr);
|
|
FREE_AND_SET_NULL(sSlotMachine);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
# undef tTimer
|
|
# undef tTimer2
|
|
|
|
// Determine the biases for this round. There can be at most two biases, one of
|
|
// which would need to be a ReelTime bias.
|
|
//
|
|
// HOW IT WORKS:
|
|
// If the machine is already biased toward 7's, keep this bias.
|
|
//
|
|
// Otherwise, there are up to three draws. You first draw to see if you'll get
|
|
// to draw a Special bias. If so, then you draw for the Special bias (and can
|
|
// still potentially miss).
|
|
//
|
|
// If you didn't get to draw a Special bias, missed a Special bias, or drew a
|
|
// ReelTime bias, then you can still try to draw a Regular bias.
|
|
static void DrawMachineBias(void)
|
|
{
|
|
u8 whichBias;
|
|
|
|
if (sSlotMachine->reelTimeSpinsLeft == 0)
|
|
{
|
|
if (!(sSlotMachine->machineBias & (BIAS_STRAIGHT_7 | BIAS_MIXED_7)))
|
|
{
|
|
if (ShouldTrySpecialBias())
|
|
{
|
|
whichBias = TrySelectBias_Special();
|
|
if (whichBias != ARRAY_COUNT(sBiasesSpecial)) // A bias was selected
|
|
{
|
|
sSlotMachine->machineBias |= sBiasesSpecial[whichBias];
|
|
|
|
// ReelTime was not selected; don't add other biases
|
|
if (whichBias != 1) return;
|
|
}
|
|
}
|
|
|
|
whichBias = TrySelectBias_Regular();
|
|
if (whichBias != ARRAY_COUNT(sBiasesRegular)) // A bias was selected
|
|
sSlotMachine->machineBias |= sBiasesRegular[whichBias];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reset `didNotFailBias` to match `machineBias`.
|
|
static void ResetBiasFailure(void)
|
|
{
|
|
sSlotMachine->didNotFailBias = FALSE;
|
|
if (sSlotMachine->machineBias)
|
|
sSlotMachine->didNotFailBias = TRUE;
|
|
}
|
|
|
|
// See sBiasSymbols for each bias's corresponding symbol.
|
|
static u8 GetBiasSymbol(u8 machineBias)
|
|
{
|
|
u8 i;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
if (machineBias & 1)
|
|
return sBiasSymbols[i];
|
|
machineBias >>= 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Decides whether you will be given the opportunity to draw for a Special bias.
|
|
// Depends on your bet and the machine you're using.
|
|
//
|
|
// The probability of getting to draw a Special is miniscule if you don't bet 3
|
|
// coins: barely 1% even on the luckiest machine.
|
|
//
|
|
// The odds increase to roughly ~5% if you bet 3 coins.
|
|
static bool8 ShouldTrySpecialBias(void)
|
|
{
|
|
u8 rval = Random();
|
|
if (sSpecialDrawOdds[sSlotMachine->machineId][sSlotMachine->bet - 1] > rval)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
// Draws for a Special bias. Note that even when you're given the opportunity to
|
|
// draw a Special bias, you can still miss.
|
|
//
|
|
// On the luckiest machine, there's a 61% chance of drawing no Special bias. On
|
|
// the unluckiest, a 73% chance.
|
|
static u8 TrySelectBias_Special(void)
|
|
{
|
|
s16 whichBias;
|
|
|
|
for (whichBias = 0; whichBias < (int)ARRAY_COUNT(sBiasesSpecial); whichBias++)
|
|
{
|
|
s16 rval = Random() & 0xff;
|
|
s16 value = sBiasProbabilities_Special[whichBias][sSlotMachine->machineId];
|
|
if (value > rval)
|
|
break;
|
|
}
|
|
return whichBias;
|
|
}
|
|
|
|
static u8 TrySelectBias_Regular(void)
|
|
{
|
|
s16 whichBias;
|
|
|
|
for (whichBias = 0; whichBias < (int)ARRAY_COUNT(sBiasesRegular); whichBias++)
|
|
{
|
|
s16 rval = Random() & 0xff;
|
|
s16 value = sBiasProbabilities_Regular[whichBias][sSlotMachine->machineId];
|
|
|
|
// Boost odds of BIAS_POWER if it's a lucky game.
|
|
if (whichBias == 0 && sSlotMachine->luckyGame == TRUE)
|
|
{
|
|
value += 10;
|
|
if (value > 0x100)
|
|
value = 0x100;
|
|
}
|
|
// Reduce odds of BIAS_REPLAY if it's a lucky game
|
|
else if (whichBias == 4 && sSlotMachine->luckyGame == TRUE)
|
|
{
|
|
value -= 10;
|
|
if (value < 0)
|
|
value = 0;
|
|
}
|
|
if (value > rval)
|
|
break;
|
|
}
|
|
return whichBias;
|
|
}
|
|
|
|
// Return the probability of drawing the given number of ReelTime spins.
|
|
//
|
|
// This depends on whether it is a lucky game and the number of Power bolts you
|
|
// have collected.
|
|
static u8 GetReelTimeSpinProbability(u8 spins)
|
|
{
|
|
if (sSlotMachine->luckyGame == FALSE)
|
|
return sReelTimeProbabilities_NormalGame[spins][sSlotMachine->pikaPowerBolts];
|
|
else
|
|
return sReelTimeProbabilities_LuckyGame[spins][sSlotMachine->pikaPowerBolts];
|
|
}
|
|
|
|
// The way this is computed skews the odds much more toward drawing a 0 than
|
|
// intended. It initially checks whether you draw a 0 (using the intended
|
|
// probability). It then tries to draw positive values, but if these draws all
|
|
// miss, you'll still draw a 0.
|
|
//
|
|
// As a result, even when the power gauge is maxed out, you still have a ~30%
|
|
// chance of drawing 0 spins. See sReelTimeProbabilities for more details.
|
|
//
|
|
// Drawing a random number via a cumulative pdf would have prevented this.
|
|
static void GetReelTimeDraw(void)
|
|
{
|
|
u8 rval;
|
|
s16 spins;
|
|
|
|
sSlotMachine->reelTimeDraw = 0;
|
|
rval = Random();
|
|
if (rval < GetReelTimeSpinProbability(0))
|
|
return;
|
|
for (spins = 5; spins > 0; spins--)
|
|
{
|
|
rval = Random();
|
|
if (rval < GetReelTimeSpinProbability(spins))
|
|
break;
|
|
}
|
|
sSlotMachine->reelTimeDraw = spins;
|
|
}
|
|
|
|
// Returns true if the ReelTime machine should explode. Each time we check,
|
|
// the odds of explosion increase.
|
|
static bool8 ShouldReelTimeMachineExplode(u16 check)
|
|
{
|
|
u16 rval = Random() & 0xff;
|
|
if (rval < sReelTimeExplodeProbability[check])
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static u16 ReelTimeSpeed(void)
|
|
{
|
|
u8 i = 0;
|
|
u8 rval;
|
|
u8 value;
|
|
if (sSlotMachine->netCoinLoss >= 300)
|
|
i = 4;
|
|
else if (sSlotMachine->netCoinLoss >= 250)
|
|
i = 3;
|
|
else if (sSlotMachine->netCoinLoss >= 200)
|
|
i = 2;
|
|
else if (sSlotMachine->netCoinLoss >= 150)
|
|
i = 1;
|
|
|
|
rval = Random() % 100;
|
|
value = sReelTimeSpeed_Probabilities[i][0];
|
|
if (rval < value)
|
|
return REEL_HALF_SPEED;
|
|
|
|
rval = Random() % 100;
|
|
value = sReelTimeSpeed_Probabilities[i][1] + sQuarterSpeed_ProbabilityBoost[sSlotMachine->reelTimeSpinsUsed];
|
|
if (rval < value)
|
|
return REEL_QUARTER_SPEED;
|
|
|
|
return REEL_NORMAL_SPEED;
|
|
}
|
|
|
|
static void CheckMatch(void)
|
|
{
|
|
sSlotMachine->matches = 0;
|
|
CheckMatch_CenterRow();
|
|
if (sSlotMachine->bet > 1)
|
|
CheckMatch_TopAndBottom();
|
|
if (sSlotMachine->bet > 2)
|
|
CheckMatch_Diagonals();
|
|
}
|
|
|
|
static void CheckMatch_CenterRow(void)
|
|
{
|
|
u8 sym1, sym2, sym3, match;
|
|
|
|
sym1 = GetSymbolAtRest(LEFT_REEL, 2);
|
|
sym2 = GetSymbolAtRest(MIDDLE_REEL, 2);
|
|
sym3 = GetSymbolAtRest(RIGHT_REEL, 2);
|
|
match = GetMatchFromSymbols(sym1, sym2, sym3);
|
|
if (match != MATCH_NONE)
|
|
{
|
|
sSlotMachine->payout += sSlotPayouts[match];
|
|
sSlotMachine->matches |= sSlotMatchFlags[match];
|
|
FlashMatchLine(MATCH_MIDDLE_ROW);
|
|
}
|
|
}
|
|
|
|
static void CheckMatch_TopAndBottom(void)
|
|
{
|
|
u8 sym1, sym2, sym3, match;
|
|
|
|
sym1 = GetSymbolAtRest(LEFT_REEL, 1);
|
|
sym2 = GetSymbolAtRest(MIDDLE_REEL, 1);
|
|
sym3 = GetSymbolAtRest(RIGHT_REEL, 1);
|
|
match = GetMatchFromSymbols(sym1, sym2, sym3);
|
|
if (match != MATCH_NONE)
|
|
{
|
|
if (match == MATCH_CHERRY)
|
|
match = MATCH_TOPBOT_CHERRY;
|
|
sSlotMachine->payout += sSlotPayouts[match];
|
|
sSlotMachine->matches |= sSlotMatchFlags[match];
|
|
FlashMatchLine(MATCH_TOP_ROW);
|
|
}
|
|
sym1 = GetSymbolAtRest(LEFT_REEL, 3);
|
|
sym2 = GetSymbolAtRest(MIDDLE_REEL, 3);
|
|
sym3 = GetSymbolAtRest(RIGHT_REEL, 3);
|
|
match = GetMatchFromSymbols(sym1, sym2, sym3);
|
|
if (match != MATCH_NONE)
|
|
{
|
|
if (match == MATCH_CHERRY)
|
|
match = MATCH_TOPBOT_CHERRY;
|
|
sSlotMachine->payout += sSlotPayouts[match];
|
|
sSlotMachine->matches |= sSlotMatchFlags[match];
|
|
FlashMatchLine(MATCH_BOTTOM_ROW);
|
|
}
|
|
}
|
|
|
|
static void CheckMatch_Diagonals(void)
|
|
{
|
|
u8 sym1, sym2, sym3, match;
|
|
|
|
sym1 = GetSymbolAtRest(LEFT_REEL, 1);
|
|
sym2 = GetSymbolAtRest(MIDDLE_REEL, 2);
|
|
sym3 = GetSymbolAtRest(RIGHT_REEL, 3);
|
|
match = GetMatchFromSymbols(sym1, sym2, sym3);
|
|
if (match != MATCH_NONE)
|
|
{
|
|
// Don't add payout for cherry, since it's already counted in
|
|
// CheckMatch_TopAndBottom().
|
|
if (match != MATCH_CHERRY)
|
|
{
|
|
sSlotMachine->payout += sSlotPayouts[match];
|
|
sSlotMachine->matches |= sSlotMatchFlags[match];
|
|
}
|
|
FlashMatchLine(MATCH_NWSE_DIAG);
|
|
}
|
|
sym1 = GetSymbolAtRest(LEFT_REEL, 3);
|
|
sym2 = GetSymbolAtRest(MIDDLE_REEL, 2);
|
|
sym3 = GetSymbolAtRest(RIGHT_REEL, 1);
|
|
match = GetMatchFromSymbols(sym1, sym2, sym3);
|
|
if (match != MATCH_NONE)
|
|
{
|
|
// Don't add payout for cherry, since it's already counted in
|
|
// CheckMatch_TopAndBottom().
|
|
if (match != MATCH_CHERRY)
|
|
{
|
|
sSlotMachine->payout += sSlotPayouts[match];
|
|
sSlotMachine->matches |= sSlotMatchFlags[match];
|
|
}
|
|
FlashMatchLine(MATCH_NESW_DIAG);
|
|
}
|
|
}
|
|
|
|
static u8 GetMatchFromSymbols(u8 sym1, u8 sym2, u8 sym3)
|
|
{
|
|
if (sym1 == sym2 && sym1 == sym3)
|
|
return sSymbolToMatch[sym1];
|
|
if (sym1 == SYMBOL_7_RED && sym2 == SYMBOL_7_RED && sym3 == SYMBOL_7_BLUE)
|
|
return MATCH_MIXED_7;
|
|
if (sym1 == SYMBOL_7_BLUE && sym2 == SYMBOL_7_BLUE && sym3 == SYMBOL_7_RED)
|
|
return MATCH_MIXED_7;
|
|
if (sym1 == SYMBOL_CHERRY)
|
|
return MATCH_CHERRY;
|
|
return MATCH_NONE;
|
|
}
|
|
|
|
static void AwardPayout(void)
|
|
{
|
|
Task_Payout(CreateTask(Task_Payout, 4));
|
|
}
|
|
|
|
static bool8 IsFinalTask_Task_Payout(void)
|
|
{
|
|
if (FindTaskIdByFunc(Task_Payout) == TAIL_SENTINEL)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static void Task_Payout(u8 taskId)
|
|
{
|
|
while (sPayoutTasks[gTasks[taskId].data[0]](&gTasks[taskId]))
|
|
;
|
|
}
|
|
|
|
#define tState data[0]
|
|
#define tTimer data[1]
|
|
|
|
static bool8 PayoutTask_Init(struct Task *task)
|
|
{
|
|
if (IsMatchLineDoneFlashingBeforePayout())
|
|
{
|
|
task->tState++; // PAYOUT_TASK_GIVE_PAYOUT
|
|
if (sSlotMachine->payout == 0)
|
|
{
|
|
task->tState = PAYOUT_TASK_FREE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
static bool8 PayoutTask_GivePayout(struct Task *task)
|
|
{
|
|
if (!task->tTimer--)
|
|
{
|
|
if (IsFanfareTaskInactive())
|
|
PlaySE(SE_PIN);
|
|
sSlotMachine->payout--;
|
|
if (sSlotMachine->coins < MAX_COINS)
|
|
sSlotMachine->coins++;
|
|
task->tTimer = 8;
|
|
if (JOY_HELD(A_BUTTON))
|
|
task->tTimer = 4;
|
|
}
|
|
if (IsFanfareTaskInactive() && JOY_NEW(START_BUTTON))
|
|
{
|
|
PlaySE(SE_PIN);
|
|
sSlotMachine->coins += sSlotMachine->payout;
|
|
if (sSlotMachine->coins > MAX_COINS)
|
|
sSlotMachine->coins = MAX_COINS;
|
|
sSlotMachine->payout = 0;
|
|
}
|
|
if (sSlotMachine->payout == 0)
|
|
task->tState++; // PAYOUT_TASK_FREE
|
|
return FALSE;
|
|
}
|
|
|
|
static bool8 PayoutTask_Free(struct Task *task)
|
|
{
|
|
if (TryStopMatchLinesFlashing())
|
|
DestroyTask(FindTaskIdByFunc(Task_Payout));
|
|
return FALSE;
|
|
}
|
|
|
|
#undef tState
|
|
#undef tTimer
|
|
|
|
// Get the symbol at position `offset` below the top of the reel's tape. Note
|
|
// that if `offset` is negative, it wraps around to the bottom of the tape.
|
|
// .-----------------.
|
|
// | [ ] | [ ] | [ ] | <- offset = 0
|
|
// /-----|-----|-----\
|
|
// screen -> | [ ] | [ ] | [ ] | <- offset = 1
|
|
// | [ ] | [ ] | [ ] | <- offset = 2
|
|
// | [ ] | [ ] | [ ] | <- offset = 3
|
|
// \-----|-----|-----/
|
|
// | ... | ... | ... |
|
|
// | [ ] | [ ] | [ ] | <- offset = 20
|
|
// .-----------------.
|
|
static u8 GetSymbolAtRest(u8 reel, s16 offset)
|
|
{
|
|
s16 pos = (sSlotMachine->reelPositions[reel] + offset) % SYMBOLS_PER_REEL;
|
|
if (pos < 0)
|
|
pos += SYMBOLS_PER_REEL;
|
|
return sReelSymbols[reel][pos];
|
|
}
|
|
|
|
// Calculates GetSymbolAtRest as if the reel were snapped downwards into place.
|
|
static u8 GetSymbol(u8 reel, s16 offset)
|
|
{
|
|
s16 inc = 0;
|
|
s16 pixelOffset = sSlotMachine->reelPixelOffsets[reel] % REEL_SYMBOL_HEIGHT;
|
|
if (pixelOffset != 0)
|
|
inc = -1;
|
|
return GetSymbolAtRest(reel, offset + inc);
|
|
}
|
|
|
|
static u8 GetReelTimeSymbol(s16 offset)
|
|
{
|
|
s16 newPosition = (sSlotMachine->reeltimePosition + offset) % REELTIME_SYMBOLS;
|
|
if (newPosition < 0)
|
|
newPosition += REELTIME_SYMBOLS;
|
|
return sReelTimeSymbols[newPosition];
|
|
}
|
|
|
|
static void AdvanceSlotReel(u8 reelIndex, s16 value)
|
|
{
|
|
sSlotMachine->reelPixelOffsets[reelIndex] += value;
|
|
sSlotMachine->reelPixelOffsets[reelIndex] %= REEL_HEIGHT;
|
|
sSlotMachine->reelPositions[reelIndex] = SYMBOLS_PER_REEL - sSlotMachine->reelPixelOffsets[reelIndex] / REEL_SYMBOL_HEIGHT;
|
|
}
|
|
|
|
// Advances the reel no further than the next symbol. Returns the remaining
|
|
// pixels until the next symbol.
|
|
s16 AdvanceSlotReelToNextSymbol(u8 reelIndex, s16 value)
|
|
{
|
|
s16 offset = sSlotMachine->reelPixelOffsets[reelIndex] % REEL_SYMBOL_HEIGHT;
|
|
if (offset != 0)
|
|
{
|
|
if (offset < value)
|
|
value = offset;
|
|
AdvanceSlotReel(reelIndex, value);
|
|
offset = sSlotMachine->reelPixelOffsets[reelIndex] % REEL_SYMBOL_HEIGHT;
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
static void AdvanceReeltimeReel(s16 value)
|
|
{
|
|
sSlotMachine->reeltimePixelOffset += value;
|
|
sSlotMachine->reeltimePixelOffset %= REELTIME_REEL_HEIGHT;
|
|
sSlotMachine->reeltimePosition = REELTIME_SYMBOLS - sSlotMachine->reeltimePixelOffset / REELTIME_SYMBOL_HEIGHT;
|
|
}
|
|
|
|
// Advances the reel no further than the next symbol. Returns the remaining
|
|
// pixels until the next symbol.
|
|
s16 AdvanceReeltimeReelToNextSymbol(s16 value)
|
|
{
|
|
s16 offset = sSlotMachine->reeltimePixelOffset % REELTIME_SYMBOL_HEIGHT;
|
|
if (offset != 0)
|
|
{
|
|
if (offset < value)
|
|
value = offset;
|
|
AdvanceReeltimeReel(value);
|
|
offset = sSlotMachine->reeltimePixelOffset % REELTIME_SYMBOL_HEIGHT;
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
#define tState data[0]
|
|
#define tExtraTurns data[1]
|
|
#define tShockMagnitude data[1]
|
|
#define tTimer data[2]
|
|
#define tMoving data[14]
|
|
#define tReelId data[15]
|
|
|
|
static void CreateReelTasks(void)
|
|
{
|
|
u8 i;
|
|
for (i = 0; i < NUM_REELS; i++)
|
|
{
|
|
u8 taskId = CreateTask(Task_Reel, 2);
|
|
gTasks[taskId].tReelId = i;
|
|
sSlotMachine->slotReelTasks[i] = taskId;
|
|
Task_Reel(taskId);
|
|
}
|
|
}
|
|
|
|
static void SpinSlotReel(u8 reelIndex)
|
|
{
|
|
gTasks[sSlotMachine->slotReelTasks[reelIndex]].tState = REEL_TASK_SPIN;
|
|
gTasks[sSlotMachine->slotReelTasks[reelIndex]].tMoving = TRUE;
|
|
}
|
|
|
|
static void StopSlotReel(u8 reelIndex)
|
|
{
|
|
gTasks[sSlotMachine->slotReelTasks[reelIndex]].tState = REEL_TASK_DECIDE_STOP;
|
|
}
|
|
|
|
static bool8 IsSlotReelMoving(u8 reelIndex)
|
|
{
|
|
return gTasks[sSlotMachine->slotReelTasks[reelIndex]].tMoving;
|
|
}
|
|
|
|
static void Task_Reel(u8 taskId)
|
|
{
|
|
while (sReelTasks[gTasks[taskId].tState](&gTasks[taskId]))
|
|
;
|
|
}
|
|
|
|
static bool8 ReelTask_StayStill(struct Task *task)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static bool8 ReelTask_Spin(struct Task *task)
|
|
{
|
|
AdvanceSlotReel(task->tReelId, sSlotMachine->reelSpeed);
|
|
return FALSE;
|
|
}
|
|
|
|
// In ReelTime, the reel stops immediately. Otherwise, the game may manipulate
|
|
// the results by stopping after at most 4 extra turns. The exact behavior
|
|
// differs depending on whether the machine has a bias.
|
|
//
|
|
// If the machine has a bias, it will try to match the bias symbol in each reel.
|
|
//
|
|
// Otherwise, if the machine doesn't have a bias or it could not line up the
|
|
// bias symbol in any of the previous reels, it will perform the NoBias stopping
|
|
// routine, which manipulates the outcome so the player loses.
|
|
static bool8 ReelTask_DecideStop(struct Task *task)
|
|
{
|
|
task->tState++; // REEL_TASK_STOP_MOVE
|
|
sSlotMachine->winnerRows[task->tReelId] = 0;
|
|
sSlotMachine->reelExtraTurns[task->tReelId] = 0;
|
|
|
|
if (sSlotMachine->reelTimeSpinsLeft == 0)
|
|
{
|
|
if (sSlotMachine->machineBias == 0 || !sSlotMachine->didNotFailBias || !sDecideStop_Bias[task->tReelId]())
|
|
{
|
|
sSlotMachine->didNotFailBias = FALSE;
|
|
sDecideStop_NoBias[task->tReelId]();
|
|
}
|
|
}
|
|
task->tExtraTurns = sSlotMachine->reelExtraTurns[task->tReelId];
|
|
return TRUE;
|
|
}
|
|
|
|
// Go to the next symbol, then add any extra turns.
|
|
static bool8 ReelTask_MoveToStop(struct Task *task)
|
|
{
|
|
u16 reelStopShocks[ARRAY_COUNT(sReelStopShocks)];
|
|
s16 reelPixelPos;
|
|
|
|
memcpy(reelStopShocks, sReelStopShocks, sizeof(sReelStopShocks));
|
|
reelPixelPos = sSlotMachine->reelPixelOffsets[task->tReelId] % REEL_SYMBOL_HEIGHT;
|
|
if (reelPixelPos != 0)
|
|
reelPixelPos = AdvanceSlotReelToNextSymbol(task->tReelId, sSlotMachine->reelSpeed);
|
|
else if (sSlotMachine->reelExtraTurns[task->tReelId])
|
|
{
|
|
sSlotMachine->reelExtraTurns[task->tReelId]--;
|
|
AdvanceSlotReel(task->tReelId, sSlotMachine->reelSpeed);
|
|
reelPixelPos = sSlotMachine->reelPixelOffsets[task->tReelId] % REEL_SYMBOL_HEIGHT;
|
|
}
|
|
|
|
if (reelPixelPos == 0 && sSlotMachine->reelExtraTurns[task->tReelId] == 0)
|
|
{
|
|
task->tState++; // REEL_TASK_STOP_SHAKE
|
|
task->tShockMagnitude = reelStopShocks[task->tExtraTurns];
|
|
task->tTimer = 0;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// The reel shakes a little at the selected symbol before settling.
|
|
static bool8 ReelTask_ShakingStop(struct Task *task)
|
|
{
|
|
sSlotMachine->reelShockOffsets[task->tReelId] = task->tShockMagnitude;
|
|
task->tShockMagnitude = -task->tShockMagnitude;
|
|
task->tTimer++;
|
|
if ((task->tTimer & 0x3) == 0)
|
|
task->tShockMagnitude >>= 1;
|
|
if (task->tShockMagnitude == 0)
|
|
{
|
|
task->tState = 0;
|
|
task->tMoving = FALSE;
|
|
sSlotMachine->reelShockOffsets[task->tReelId] = 0;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
#undef tState
|
|
#undef tExtraTurns
|
|
#undef tShockMagnitude
|
|
#undef tTimer
|
|
#undef tMoving
|
|
#undef tReelId
|
|
|
|
// We pass along two symbols to bias toward. If the machine is biased toward
|
|
// 7's, we pass both the 7 symbols. Otherwise, we just pass the bias symbol
|
|
// twice.
|
|
static bool8 DecideStop_Bias_Reel1(void)
|
|
{
|
|
u8 sym2 = GetBiasSymbol(sSlotMachine->machineBias);
|
|
u8 sym1 = sym2;
|
|
if (sSlotMachine->machineBias & (BIAS_STRAIGHT_7 | BIAS_MIXED_7))
|
|
{
|
|
sym1 = SYMBOL_7_RED;
|
|
sym2 = SYMBOL_7_BLUE;
|
|
}
|
|
return sDecideStop_Bias_Reel1_Bets[sSlotMachine->bet - 1](sym1, sym2);
|
|
}
|
|
|
|
// The biasSymbol for subsequent reels is determined based on which of the bias
|
|
// symbols can be found in reel 1. This really only matters when the machine is
|
|
// biased toward 7's. It will try to match a 7 of the same color as reel 1.
|
|
static bool8 EitherSymbolAtPos_Reel1(s16 pos, u8 sym1, u8 sym2)
|
|
{
|
|
u8 sym = GetSymbol(LEFT_REEL, pos);
|
|
if (sym == sym1 || sym == sym2)
|
|
{
|
|
sSlotMachine->biasSymbol = sym;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// Returns true if there are cherries on screen in reel 1 after the given number
|
|
// of turns.
|
|
static bool8 AreCherriesOnScreen_Reel1(s16 turns)
|
|
{
|
|
if (GetSymbol(LEFT_REEL, 1 - turns) == SYMBOL_CHERRY
|
|
|| GetSymbol(LEFT_REEL, 2 - turns) == SYMBOL_CHERRY
|
|
|| GetSymbol(LEFT_REEL, 3 - turns) == SYMBOL_CHERRY)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static bool8 BiasedTowardCherryOr7s(void)
|
|
{
|
|
if (sSlotMachine->machineBias & (BIAS_STRAIGHT_7 | BIAS_MIXED_7 | BIAS_CHERRY))
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
// If a bias symbol appears in the center of reel 1 within the next 4 turns,
|
|
// stop there. That symbol becomes the biasSymbol for the subsequent reels.
|
|
static bool8 DecideStop_Bias_Reel1_Bet1(u8 sym1, u8 sym2)
|
|
{
|
|
s16 i;
|
|
|
|
for (i = 0; i <= MAX_EXTRA_TURNS; i++)
|
|
{
|
|
if (EitherSymbolAtPos_Reel1(2 - i, sym1, sym2))
|
|
{
|
|
sSlotMachine->winnerRows[LEFT_REEL] = 2;
|
|
sSlotMachine->reelExtraTurns[LEFT_REEL] = i;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// There is slightly different behavior depending on the machine's bias.
|
|
//
|
|
// Bias toward cherry or 7s:
|
|
// - Check if a cherry or 7 is currently on screen. If so, stop immediately.
|
|
// - Roll up to 4 extra turns to see if a cherry or 7 enters the screen:
|
|
// - If it enters after 1 turn, stop the reel when it gets the bottom row.
|
|
// - Otherwise, if it enters before the 4th turn, stop the reel when it gets
|
|
// to the middle row.
|
|
// - If it enters on the 4th turn, stop here. It will be in the top row.
|
|
//
|
|
// Other bias:
|
|
// - This is very similar, except the game is checking for the bias symbol
|
|
// rather than cherries / 7s.
|
|
//
|
|
// However, the game adds an additional constraint: it will not stop if there
|
|
// will be any cherries on screen. Presumably, this ensures that you will not
|
|
// get any matches if you fail to line up the bias symbol in the remaining
|
|
// reels.
|
|
//
|
|
// This is programmed in such a way that it excludes more options than
|
|
// necessary. If there are cherries in the two positions below the bias symbol,
|
|
// it will skip over this option, even if those cherries would not have ended
|
|
// up on screen.
|
|
static bool8 DecideStop_Bias_Reel1_Bet2or3(u8 sym1, u8 sym2)
|
|
{
|
|
s16 i;
|
|
bool8 cherry7Bias = BiasedTowardCherryOr7s();
|
|
if (cherry7Bias || !AreCherriesOnScreen_Reel1(0))
|
|
{
|
|
// Check the current screen
|
|
for (i = 1; i <= 3; i++)
|
|
{
|
|
if (EitherSymbolAtPos_Reel1(i, sym1, sym2))
|
|
{
|
|
sSlotMachine->winnerRows[0] = i;
|
|
sSlotMachine->reelExtraTurns[0] = 0;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check the next 4 turns
|
|
for (i = 1; i <= MAX_EXTRA_TURNS; i++)
|
|
{
|
|
bool8 cherry7BiasCopy = cherry7Bias; // redundant
|
|
if (cherry7BiasCopy || !AreCherriesOnScreen_Reel1(i))
|
|
{
|
|
if (EitherSymbolAtPos_Reel1(1 - i, sym1, sym2))
|
|
{
|
|
if (i == 1 && (cherry7BiasCopy || !AreCherriesOnScreen_Reel1(3)))
|
|
{
|
|
sSlotMachine->winnerRows[0] = 3;
|
|
sSlotMachine->reelExtraTurns[0] = 3;
|
|
return TRUE;
|
|
}
|
|
if (i <= 3 && (cherry7BiasCopy || !AreCherriesOnScreen_Reel1(i + 1)))
|
|
{
|
|
sSlotMachine->winnerRows[0] = 2;
|
|
sSlotMachine->reelExtraTurns[0] = i + 1;
|
|
return TRUE;
|
|
}
|
|
sSlotMachine->winnerRows[0] = 1;
|
|
sSlotMachine->reelExtraTurns[0] = i;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static bool8 DecideStop_Bias_Reel2(void)
|
|
{
|
|
return sDecideStop_Bias_Reel2_Bets[sSlotMachine->bet - 1]();
|
|
}
|
|
|
|
// Turn at most 4 extra turns to try to line up the bias symbol in the same row
|
|
// as reel 1.
|
|
static bool8 DecideStop_Bias_Reel2_Bet1or2(void)
|
|
{
|
|
s16 i;
|
|
s16 reel1BiasRow = sSlotMachine->winnerRows[0];
|
|
|
|
for (i = 0; i <= MAX_EXTRA_TURNS; i++)
|
|
{
|
|
if (GetSymbol(MIDDLE_REEL, reel1BiasRow - i) == sSlotMachine->biasSymbol)
|
|
{
|
|
sSlotMachine->winnerRows[1] = reel1BiasRow;
|
|
sSlotMachine->reelExtraTurns[1] = i;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// Checks whether it can match the bias symbol diagonally, and sometimes skews
|
|
// toward this type of match rather than a match straight across.
|
|
//
|
|
// The behavior is different depending on where the bias symbol landed in
|
|
// reel 1:
|
|
//
|
|
// Landed in middle row:
|
|
// A diagonal match is impossible. Just try to match the bias symbol in the
|
|
// middle row of reel 2 within 4 turns.
|
|
//
|
|
// Landed in top/bottom row:
|
|
// - If it would take 2 or 3 turns to get the bias symbol into the same row as
|
|
// reel 1, force a diagonal match by stopping it in the middle row instead.
|
|
// - Check if the bias symbol is already in the same row as reel 1, or if it
|
|
// takes 1 or 4 turns to get it there. If so, stop when it reaches that row.
|
|
// - Otherwise, check if the bias symbol is already in the middle row of
|
|
// reel 2. If so, stop here.
|
|
//
|
|
// So in how many more cases would betting 3 coins let you win compared to
|
|
// betting 2?
|
|
// Not many. Most of the time, the game would have matched the symbol in the
|
|
// same row as reel 1 if you had bet 2 coins. Betting 3 effectively adds
|
|
// coverage for only two additional cases:
|
|
// - Bias symbol is in top row of reel 1 and bias symbol is currently in
|
|
// middle row of reel 2.
|
|
// - Bias symbol is in bottom row of reel 1 and bias symbol could get to the
|
|
// middle row of reel 2 in 4 turns.
|
|
//
|
|
// Assuming this is the implementation Game Freak intended, the game effectively
|
|
// turns straight matches into diagonal matches with 2/5 probability.
|
|
// Presumably, this makes the player feel fortunate that they bet 3 coins rather
|
|
// than 2, even though most times the game would have still forced a match with
|
|
// only 2 coins.
|
|
static bool8 DecideStop_Bias_Reel2_Bet3(void)
|
|
{
|
|
s16 i;
|
|
// If you can line up the bias symbol in the same row as reel 1 within 4
|
|
// turns
|
|
if (DecideStop_Bias_Reel2_Bet1or2())
|
|
{
|
|
// If bias symbol is not in the middle row of reel 1 and it takes either
|
|
// 2 or 3 turns to get it in the same row for reel 2
|
|
if (sSlotMachine->winnerRows[0] != 2 && sSlotMachine->reelExtraTurns[1] > 1 && sSlotMachine->reelExtraTurns[1] != 4)
|
|
{
|
|
// Try turning this into a diagonal match by lining up the bias
|
|
// symbol in the middle row of reel 2 within 4 turns.
|
|
for (i = 0; i <= MAX_EXTRA_TURNS; i++)
|
|
{
|
|
if (GetSymbol(MIDDLE_REEL, 2 - i) == sSlotMachine->biasSymbol)
|
|
{
|
|
sSlotMachine->winnerRows[1] = 2;
|
|
sSlotMachine->reelExtraTurns[1] = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// If you can't line up the bias symbol in the same row in 4 turns, and the
|
|
// bias symbol is not in the middle row of reel 1
|
|
if (sSlotMachine->winnerRows[0] != 2)
|
|
{
|
|
// Try to match the bias symbol in middle row of reel 2 within 4 turns.
|
|
// Adds coverage for the two cases mentioned above.
|
|
for (i = 0; i <= MAX_EXTRA_TURNS; i++)
|
|
{
|
|
if (GetSymbol(MIDDLE_REEL, 2 - i) == sSlotMachine->biasSymbol)
|
|
{
|
|
sSlotMachine->winnerRows[1] = 2;
|
|
sSlotMachine->reelExtraTurns[1] = i;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// If the machine is biased toward mixed 7's, swap the color of the bias symbol
|
|
// from red 7 to blue 7, or vice versa.
|
|
static bool8 DecideStop_Bias_Reel3(void)
|
|
{
|
|
u8 biasSymbol = sSlotMachine->biasSymbol;
|
|
if (sSlotMachine->machineBias & BIAS_MIXED_7)
|
|
{
|
|
biasSymbol = SYMBOL_7_RED;
|
|
if (sSlotMachine->biasSymbol == SYMBOL_7_RED)
|
|
{
|
|
biasSymbol = SYMBOL_7_BLUE;
|
|
}
|
|
}
|
|
return sDecideStop_Bias_Reel3_Bets[sSlotMachine->bet - 1](biasSymbol);
|
|
}
|
|
|
|
// Turn at most 4 extra turns to try to line up the bias symbol in the same
|
|
// row as reel 2.
|
|
static bool8 DecideStop_Bias_Reel3_Bet1or2(u8 biasSymbol)
|
|
{
|
|
s16 i;
|
|
s16 reel2BiasRow = sSlotMachine->winnerRows[1];
|
|
|
|
for (i = 0; i <= MAX_EXTRA_TURNS; i++)
|
|
{
|
|
if (GetSymbol(RIGHT_REEL, reel2BiasRow - i) == biasSymbol)
|
|
{
|
|
sSlotMachine->winnerRows[2] = reel2BiasRow;
|
|
sSlotMachine->reelExtraTurns[2] = i;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// Try to complete a match in reel 3 by lining up a bias symbol with the bias
|
|
// symbols from the first two reels.
|
|
static bool8 DecideStop_Bias_Reel3_Bet3(u8 biasSymbol)
|
|
{
|
|
s16 i;
|
|
s16 biasRow;
|
|
|
|
// First two bias symbols in the same row. Try to line up bias symbol in
|
|
// same the row here too
|
|
if (sSlotMachine->winnerRows[0] == sSlotMachine->winnerRows[1])
|
|
return DecideStop_Bias_Reel3_Bet1or2(biasSymbol);
|
|
|
|
// Otherwise, try to line up the bias symbol diagonally
|
|
if (sSlotMachine->winnerRows[0] == 1)
|
|
biasRow = 3;
|
|
else
|
|
biasRow = 1;
|
|
for (i = 0; i <= MAX_EXTRA_TURNS; i++)
|
|
{
|
|
if (GetSymbol(RIGHT_REEL, biasRow - i) == biasSymbol)
|
|
{
|
|
sSlotMachine->reelExtraTurns[2] = i;
|
|
sSlotMachine->winnerRows[2] = biasRow;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// Advance as many turns as needed until there are no cherries on screen in
|
|
// reel 1, as cherries would cause a match.
|
|
//
|
|
// Based on the distribution of reel 1, this will add at most 3 extra turns.
|
|
static void DecideStop_NoBias_Reel1(void)
|
|
{
|
|
s16 i = 0;
|
|
|
|
while (AreCherriesOnScreen_Reel1(i) != 0)
|
|
i++;
|
|
sSlotMachine->reelExtraTurns[0] = i;
|
|
}
|
|
|
|
// If the bias symbol is one of the 7's, switch to the opposite color and return
|
|
// true. Otherwise, return false.
|
|
static bool8 IfSymbol7_SwitchColor(u8 *symbol)
|
|
{
|
|
if (*symbol == SYMBOL_7_RED)
|
|
{
|
|
*symbol = SYMBOL_7_BLUE;
|
|
return TRUE;
|
|
}
|
|
if (*symbol == SYMBOL_7_BLUE)
|
|
{
|
|
*symbol = SYMBOL_7_RED;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// If the machine doesn't have a bias, the reel stops immediately.
|
|
//
|
|
// Otherwise, the machine tries to taunt the player if it is biased toward
|
|
// straight 7's. This would only happen if the player did not stop near the
|
|
// correct-color 7, so the machine couldn't force a match.
|
|
//
|
|
// Instead, the machine now tries to line up the opposite-color 7, which is not
|
|
// a valid match.
|
|
static void DecideStop_NoBias_Reel2(void)
|
|
{
|
|
sDecideStop_NoBias_Reel2_Bets[sSlotMachine->bet - 1]();
|
|
}
|
|
|
|
// If the machine has no bias, stop immediately.
|
|
//
|
|
// Otherwise, the machine manipulates the results if all the following
|
|
// conditions are met:
|
|
// If
|
|
// - The machine is biased toward straight 7's
|
|
// - The machine managed to match a 7 in the middle of reel 1
|
|
// - The machine could not line up a 7 of the same color in reel 2
|
|
// Then
|
|
// The machine will try to line up a 7 of the opposite color in reel 2
|
|
static void DecideStop_NoBias_Reel2_Bet1(void)
|
|
{
|
|
if (sSlotMachine->winnerRows[0] != 0 && sSlotMachine->machineBias & BIAS_STRAIGHT_7)
|
|
{
|
|
// Note here and in other NoBias functions, reelExtraTurns is 0 if it
|
|
// corresponds to a previous reel. That reel has already stopped and any
|
|
// extra turns were applied.
|
|
u8 reel1MiddleSym = GetSymbol(LEFT_REEL, 2 - sSlotMachine->reelExtraTurns[0]);
|
|
if (IfSymbol7_SwitchColor(&reel1MiddleSym))
|
|
{
|
|
s16 i;
|
|
for (i = 0; i <= MAX_EXTRA_TURNS; i++)
|
|
{
|
|
if (reel1MiddleSym == GetSymbol(MIDDLE_REEL, 2 - i))
|
|
{
|
|
sSlotMachine->winnerRows[1] = 2;
|
|
sSlotMachine->reelExtraTurns[1] = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the machine has no bias, stop immediately.
|
|
//
|
|
// Otherwise, the machine manipulates the results if all the following
|
|
// conditions are met:
|
|
// If
|
|
// - The machine is biased toward straight 7's
|
|
// - The machine managed to match a 7 anywhere in reel 1
|
|
// - The machine could not line up a 7 of the same color in reel 2
|
|
// Then
|
|
// The machine will try to line up a 7 of the opposite color in reel 2
|
|
static void DecideStop_NoBias_Reel2_Bet2(void)
|
|
{
|
|
if (sSlotMachine->winnerRows[0] != 0 && sSlotMachine->machineBias & BIAS_STRAIGHT_7)
|
|
{
|
|
u8 reel1BiasSym = GetSymbol(LEFT_REEL, sSlotMachine->winnerRows[0] - sSlotMachine->reelExtraTurns[0]);
|
|
if (IfSymbol7_SwitchColor(&reel1BiasSym))
|
|
{
|
|
s16 i;
|
|
for (i = 0; i <= MAX_EXTRA_TURNS; i++)
|
|
{
|
|
if (reel1BiasSym == GetSymbol(MIDDLE_REEL, sSlotMachine->winnerRows[0] - i))
|
|
{
|
|
sSlotMachine->winnerRows[1] = sSlotMachine->winnerRows[0];
|
|
sSlotMachine->reelExtraTurns[1] = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the machine has no bias, stop immediately.
|
|
//
|
|
// Otherwise, the machine manipulates the results if all the following
|
|
// conditions are met:
|
|
// If
|
|
// - The machine is biased toward straight 7's
|
|
// - The machine managed to match a 7 anywhere in reel 1
|
|
// - The machine could not line up a 7 of the same color in reel 2
|
|
// Then
|
|
// The machine will try to line up a 7 of the opposite color in reel 2
|
|
//
|
|
// The way it tries to line up an opposite-color 7 differs depending on where
|
|
// the 7 is in reel 1:
|
|
//
|
|
// Middle row:
|
|
// Try to line up an opposite-color 7 in the middle of reel 2 within 4 turns.
|
|
//
|
|
// Top row:
|
|
// - First check for an opposite-color 7 in the top and middle rows of the
|
|
// current screen. If found, stop immediately.
|
|
// - Otherwise, check if an opposite-color 7 will enter the top row within 4
|
|
// turns.
|
|
// - If one enters in 1 or 2 turns, stop the reel when it gets to the middle
|
|
// row.
|
|
// - If one enters in 3 or 4 turns, stop the reel when it gets to the top
|
|
// row.
|
|
//
|
|
// Bottom row:
|
|
// - First check for an opposite-color 7 in the middle and bottom rows of the
|
|
// current screen. If found, stop immediately.
|
|
// - Otherwise, check if an opposite-color 7 will enter the bottom row within 4
|
|
// turns.
|
|
// - If one enters in 1 or 2 turns, stop the reel when it gets to the bottom
|
|
// row.
|
|
// - If one enters in 3 or 4 turns, stop the reel when it gets to the middle
|
|
// row.
|
|
//
|
|
// BUG: This procedure misses an opportunity to line up an opposite-color 7 in
|
|
// one scenario, when:
|
|
// - There is a 7 in the bottom row of reel 1
|
|
// - And, you can get an opposite-color 7 in the middle row of reel 2 in 4
|
|
// turns
|
|
static void DecideStop_NoBias_Reel2_Bet3(void)
|
|
{
|
|
s16 i;
|
|
s16 j;
|
|
u8 reel1BiasSym;
|
|
|
|
if (sSlotMachine->winnerRows[0] != 0 && sSlotMachine->machineBias & BIAS_STRAIGHT_7)
|
|
{
|
|
// Lined up 7 in middle of reel 1
|
|
if (sSlotMachine->winnerRows[0] == 2)
|
|
{
|
|
DecideStop_NoBias_Reel2_Bet2();
|
|
return;
|
|
}
|
|
|
|
reel1BiasSym = GetSymbol(LEFT_REEL, sSlotMachine->winnerRows[0] - sSlotMachine->reelExtraTurns[0]);
|
|
if (IfSymbol7_SwitchColor(&reel1BiasSym))
|
|
{
|
|
// Check current screen to see if there is already an opposite-color
|
|
// 7 lined up for a match.
|
|
j = 2;
|
|
if (sSlotMachine->winnerRows[0] == 3)
|
|
j = 3;
|
|
for (i = 0; i < 2; i++, j--)
|
|
{
|
|
if (reel1BiasSym == GetSymbol(MIDDLE_REEL, j))
|
|
{
|
|
sSlotMachine->winnerRows[1] = j;
|
|
sSlotMachine->reelExtraTurns[1] = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Check if opposite-color 7 will appear in same row as reel 1 in
|
|
// over the next 4 turns
|
|
for (j = 1; j <= MAX_EXTRA_TURNS; j++)
|
|
{
|
|
if (reel1BiasSym == GetSymbol(MIDDLE_REEL, sSlotMachine->winnerRows[0] - j))
|
|
{
|
|
// If 7 appeared in top row of reel 1
|
|
if (sSlotMachine->winnerRows[0] == 1)
|
|
{
|
|
if (j <= 2)
|
|
{
|
|
sSlotMachine->winnerRows[1] = 2;
|
|
sSlotMachine->reelExtraTurns[1] = j + 1;
|
|
}
|
|
else
|
|
{
|
|
sSlotMachine->winnerRows[1] = 1;
|
|
sSlotMachine->reelExtraTurns[1] = j;
|
|
}
|
|
}
|
|
// If 7 appeared in bottom row of reel 1
|
|
else
|
|
{
|
|
if (j <= 2)
|
|
{
|
|
sSlotMachine->winnerRows[1] = 3;
|
|
sSlotMachine->reelExtraTurns[1] = j;
|
|
}
|
|
else
|
|
{
|
|
sSlotMachine->winnerRows[1] = 2;
|
|
sSlotMachine->reelExtraTurns[1] = j - 1;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Returns true if the reel 1 and reel 2 symbols are opposite-color 7's.
|
|
//
|
|
// Note that if true, this does not constitue a MATCH_MIXED_7, as the first two
|
|
// reels are not the same color.
|
|
static bool8 MismatchedSyms_77(u8 sym1, u8 sym2)
|
|
{
|
|
if ((sym1 == SYMBOL_7_RED && sym2 == SYMBOL_7_BLUE) || (sym1 == SYMBOL_7_BLUE && sym2 == SYMBOL_7_RED))
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
// Returns true if the reel 1, reel 2 and reel 3 symbolss form a 7 mismatch,
|
|
// i.e. {7R, 7B, 7R} or {7B, 7R, 7B}.
|
|
static bool8 MismatchedSyms_777(u8 sym1, u8 sym2, u8 sym3)
|
|
{
|
|
if ((sym1 == SYMBOL_7_RED && sym2 == SYMBOL_7_BLUE && sym3 == SYMBOL_7_RED) ||
|
|
(sym1 == SYMBOL_7_BLUE && sym2 == SYMBOL_7_RED && sym3 == SYMBOL_7_BLUE))
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
// Returns false if either:
|
|
// - The symbols form a match (including MATCH_MIXED_7)
|
|
// - Or, the symbols form a 7 mismatch (i.e., {7R, 7B, 7R} or {7B, 7R, 7B})
|
|
//
|
|
// Note, this does not account for cherry matches.
|
|
static bool8 NeitherMatchNor7Mismatch(u8 sym1, u8 sym2, u8 sym3)
|
|
{
|
|
if ((sym1 == SYMBOL_7_RED && sym2 == SYMBOL_7_BLUE && sym3 == SYMBOL_7_RED)
|
|
|| (sym1 == SYMBOL_7_BLUE && sym2 == SYMBOL_7_RED && sym3 == SYMBOL_7_BLUE)
|
|
|| (sym1 == SYMBOL_7_RED && sym2 == SYMBOL_7_RED && sym3 == SYMBOL_7_BLUE)
|
|
|| (sym1 == SYMBOL_7_BLUE && sym2 == SYMBOL_7_BLUE && sym3 == SYMBOL_7_RED)
|
|
|| (sym1 == sym2 && sym1 == sym3))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// Spin until there's no match, or try to taunt the player with a 7 mismatch if
|
|
// they failed the straight 7 bias.
|
|
static void DecideStop_NoBias_Reel3(void)
|
|
{
|
|
sDecideStop_NoBias_Reel3_Bets[sSlotMachine->bet - 1]();
|
|
}
|
|
|
|
// Spin until there is no match in reel 3. Additionally, if the player failed a
|
|
// straight 7 bias, try to taunt them with a 7 mismatch.
|
|
//
|
|
// The way this plays out depends on the first two matched symbols.
|
|
//
|
|
// If first two symbols are the same:
|
|
// Spin until you get a symbol that won't complete a match.
|
|
//
|
|
// Otherwise, if the first two symbols are opposite-color 7's:
|
|
// - If the machine is biased toward straight 7's, then the player must have
|
|
// failed with this bias. The machine tries to taunt the player by turning
|
|
// up to 4 turns to complete a 7 mismatch (i.e., {7R, 7B, 7R} or
|
|
// {7B, 7R, 7B}).
|
|
// - Otherwise, spin until you get a symbol that won't complete a match.
|
|
static void DecideStop_NoBias_Reel3_Bet1(void)
|
|
{
|
|
s16 i = 0;
|
|
u8 sym1 = GetSymbol(LEFT_REEL, 2 - sSlotMachine->reelExtraTurns[0]);
|
|
u8 sym2 = GetSymbol(MIDDLE_REEL, 2 - sSlotMachine->reelExtraTurns[1]);
|
|
|
|
// If first two symbols match, spin until you get a non-matching symbol
|
|
if (sym1 == sym2)
|
|
{
|
|
while (TRUE)
|
|
{
|
|
u8 sym3;
|
|
if (!((sym1 == (sym3 = GetSymbol(RIGHT_REEL, 2 - i)))
|
|
|| (sym1 == SYMBOL_7_RED && sym3 == SYMBOL_7_BLUE)
|
|
|| (sym1 == SYMBOL_7_BLUE && sym3 == SYMBOL_7_RED)))
|
|
break;
|
|
i++;
|
|
}
|
|
}
|
|
// First two symbols are opposite-color 7's
|
|
else if (MismatchedSyms_77(sym1, sym2))
|
|
{
|
|
// If biased toward straight 7's, try to complete the 7 mismatch in 4
|
|
// turns
|
|
if (sSlotMachine->machineBias & BIAS_STRAIGHT_7)
|
|
{
|
|
for (i = 0; i <= MAX_EXTRA_TURNS; i++)
|
|
{
|
|
if (sym1 == GetSymbol(RIGHT_REEL, 2 - i))
|
|
{
|
|
sSlotMachine->reelExtraTurns[2] = i;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Otherwise, just spin until you get a non-matching symbol
|
|
i = 0;
|
|
while (TRUE)
|
|
{
|
|
if (sym1 != GetSymbol(RIGHT_REEL, 2 - i))
|
|
break;
|
|
i++;
|
|
}
|
|
}
|
|
sSlotMachine->reelExtraTurns[2] = i;
|
|
}
|
|
|
|
// Spin until there is no match in reel 3. Additionally, if the player failed a
|
|
// straight 7 bias, try to taunt them with a 7 mismatch.
|
|
//
|
|
// There are up to two stages, depending on the first two matched symbols:
|
|
//
|
|
// 1. [Optional] If first two symbols are opposite-color 7's in the same row and
|
|
// the machine is biased toward straight 7's:
|
|
// Check if a 7 with the same color as reel 1 appears in the same row
|
|
// within 4 turns. If so, initially advance to that position.
|
|
//
|
|
// 2. Check rows. Keep advancing the reel a turn at a time as long as:
|
|
// - There is a match in any row
|
|
// - Or, there is a 7 mismatch in any row and the machine isn't biased
|
|
// toward straight 7's
|
|
//
|
|
// Note, stage 2 is not limited to 4 turns. The reel keeps spinning until you
|
|
// lose.
|
|
static void DecideStop_NoBias_Reel3_Bet2(void)
|
|
{
|
|
s16 extraTurns = 0;
|
|
s16 i;
|
|
u8 sym1;
|
|
u8 sym2;
|
|
u8 sym3;
|
|
|
|
// Effectively, if you lined up two 7's in the same row
|
|
if (sSlotMachine->winnerRows[1] != 0 &&
|
|
sSlotMachine->winnerRows[0] == sSlotMachine->winnerRows[1] &&
|
|
sSlotMachine->machineBias & BIAS_STRAIGHT_7)
|
|
{
|
|
sym1 = GetSymbol(LEFT_REEL, sSlotMachine->winnerRows[0] - sSlotMachine->reelExtraTurns[0]);
|
|
sym2 = GetSymbol(MIDDLE_REEL, sSlotMachine->winnerRows[1] - sSlotMachine->reelExtraTurns[1]);
|
|
|
|
// If the first two 7's are opposite colors, see if you can line up a 7
|
|
// mismatch in the same row. If so, advance initially to that position.
|
|
// More turns may be added further below.
|
|
if (MismatchedSyms_77(sym1, sym2))
|
|
{
|
|
// Iterate over the next 4 turns
|
|
for (i = 0; i <= MAX_EXTRA_TURNS; i++)
|
|
{
|
|
sym3 = GetSymbol(RIGHT_REEL, sSlotMachine->winnerRows[1] - i);
|
|
if (sym1 == sym3)
|
|
{
|
|
extraTurns = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
s16 numMatches;
|
|
// Iterate over the rows of the screen after `extraTurns` turns
|
|
for (i = 1, numMatches = 0; i <= 3; i++)
|
|
{
|
|
sym1 = GetSymbol(LEFT_REEL, i - sSlotMachine->reelExtraTurns[0]);
|
|
sym2 = GetSymbol(MIDDLE_REEL, i - sSlotMachine->reelExtraTurns[1]);
|
|
sym3 = GetSymbol(RIGHT_REEL, i - extraTurns);
|
|
|
|
// This boils down to:
|
|
// If there's a match on screen, keep spinning. Otherwise, if
|
|
// there's a 7 mismatch on screen, keep spinning if the machine
|
|
// isn't biased toward straight 7's.
|
|
if (!NeitherMatchNor7Mismatch(sym1, sym2, sym3) &&
|
|
!(MismatchedSyms_777(sym1, sym2, sym3) && (sSlotMachine->machineBias & BIAS_STRAIGHT_7)))
|
|
{
|
|
numMatches++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If no matches were found, stop here. Otherwise, add an extra spin and
|
|
// check again.
|
|
if (numMatches == 0)
|
|
break;
|
|
extraTurns++;
|
|
}
|
|
sSlotMachine->reelExtraTurns[2] = extraTurns;
|
|
}
|
|
|
|
// Try to spin until there is no match in reel 3. Additionally, if the player
|
|
// failed a straight 7 bias, try to taunt them with a 7 mismatch.
|
|
//
|
|
// There are up to four stages:
|
|
//
|
|
// 1. Advance the reel as if 2 coins were bet: to mildly oversimplify, spin
|
|
// until there's no matches straight across in any rows.
|
|
//
|
|
// 2. [Optional] If you've lined up two opposite-color 7's diagonally and the
|
|
// machine is biased toward straight 7's:
|
|
// Check if a 7 with the same color as reel 1 appears in the final diagonal
|
|
// position within 4 turns. If so, advance to that position.
|
|
//
|
|
// 3. Check NWSE diagonal. Keep advancing the reel a turn at a time as long as:
|
|
// - There is a match in the diagonal
|
|
// - Or, there is a 7 mismatch in the diagonal and the machine isn't
|
|
// biased toward straight 7's
|
|
//
|
|
// 3. Check NESW diagonal. Keep advancing the reel a turn at a time as long as:
|
|
// - There is a match in the diagonal
|
|
// - Or, there is a 7 mismatch in the diagonal and the machine isn't
|
|
// biased toward straight 7's
|
|
//
|
|
// Note that stages 3 and 4 are not limited to 4 turns.
|
|
//
|
|
// Also, note that it actually is possible to win a match here. After stage 1,
|
|
// the game never again checks whether it will be matching any rows straight
|
|
// across. So any extra turns added in stages 2-4 could result in a match
|
|
// occurring straight across.
|
|
static void DecideStop_NoBias_Reel3_Bet3(void)
|
|
{
|
|
u8 sym1;
|
|
u8 sym2;
|
|
u8 sym3;
|
|
s16 row;
|
|
s16 i;
|
|
|
|
// Spin until there's no matches in any row straight across, potentially
|
|
// skewing toward a 7 mismatch. Consider this the new starting position for
|
|
// this function.
|
|
DecideStop_NoBias_Reel3_Bet2();
|
|
|
|
// Essentially, if you lined up two 7's diagonally
|
|
if (sSlotMachine->winnerRows[1] != 0 &&
|
|
sSlotMachine->winnerRows[0] != sSlotMachine->winnerRows[1] &&
|
|
sSlotMachine->machineBias & BIAS_STRAIGHT_7)
|
|
{
|
|
sym1 = GetSymbol(LEFT_REEL, sSlotMachine->winnerRows[0] - sSlotMachine->reelExtraTurns[0]);
|
|
sym2 = GetSymbol(MIDDLE_REEL, sSlotMachine->winnerRows[1] - sSlotMachine->reelExtraTurns[1]);
|
|
|
|
// If the first two 7's are opposite colors, try advancing up to 4
|
|
// additional turns to line up a diagonal 7 mismatch. More turns may be
|
|
// added further below.
|
|
if (MismatchedSyms_77(sym1, sym2))
|
|
{
|
|
row = 1;
|
|
if (sSlotMachine->winnerRows[0] == 1)
|
|
row = 3;
|
|
for (i = 0; i <= MAX_EXTRA_TURNS; i++)
|
|
{
|
|
sym3 = GetSymbol(RIGHT_REEL, row - (sSlotMachine->reelExtraTurns[2] + i));
|
|
if (sym1 == sym3)
|
|
{
|
|
sSlotMachine->reelExtraTurns[2] += i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
// Check NWSE diagonal
|
|
sym1 = GetSymbol(LEFT_REEL, 1 - sSlotMachine->reelExtraTurns[0]);
|
|
sym2 = GetSymbol(MIDDLE_REEL, 2 - sSlotMachine->reelExtraTurns[1]);
|
|
sym3 = GetSymbol(RIGHT_REEL, 3 - sSlotMachine->reelExtraTurns[2]);
|
|
if (NeitherMatchNor7Mismatch(sym1, sym2, sym3)
|
|
|| (MismatchedSyms_777(sym1, sym2, sym3) && sSlotMachine->machineBias & BIAS_STRAIGHT_7))
|
|
break;
|
|
sSlotMachine->reelExtraTurns[2]++;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
// Check NESW diagonal
|
|
sym1 = GetSymbol(LEFT_REEL, 3 - sSlotMachine->reelExtraTurns[0]);
|
|
sym2 = GetSymbol(MIDDLE_REEL, 2 - sSlotMachine->reelExtraTurns[1]);
|
|
sym3 = GetSymbol(RIGHT_REEL, 1 - sSlotMachine->reelExtraTurns[2]);
|
|
if (NeitherMatchNor7Mismatch(sym1, sym2, sym3)
|
|
|| (MismatchedSyms_777(sym1, sym2, sym3) && sSlotMachine->machineBias & BIAS_STRAIGHT_7))
|
|
break;
|
|
sSlotMachine->reelExtraTurns[2]++;
|
|
}
|
|
}
|
|
|
|
static void PressStopReelButton(u8 reelNum)
|
|
{
|
|
u8 taskId = CreateTask(Task_PressStopReelButton, 5);
|
|
gTasks[taskId].data[15] = reelNum;
|
|
Task_PressStopReelButton(taskId);
|
|
}
|
|
|
|
static void Task_PressStopReelButton(u8 taskId)
|
|
{
|
|
sReelStopButtonTasks[gTasks[taskId].data[0]](&gTasks[taskId], taskId);
|
|
}
|
|
|
|
static void StopReelButton_Press(struct Task *task, u8 taskId)
|
|
{
|
|
SetReelButtonTilemap(sReelButtonOffsets[task->data[15]], 0x62, 0x63, 0x72, 0x73);
|
|
task->data[0]++;
|
|
}
|
|
|
|
static void StopReelButton_Wait(struct Task *task, u8 taskId)
|
|
{
|
|
if (++task->data[1] > 11)
|
|
task->data[0]++;
|
|
}
|
|
|
|
static void StopReelButton_Unpress(struct Task *task, u8 taskId)
|
|
{
|
|
SetReelButtonTilemap(sReelButtonOffsets[task->data[15]], 0x42, 0x43, 0x52, 0x53);
|
|
DestroyTask(taskId);
|
|
}
|
|
|
|
static void LightenMatchLine(u8 matchLineId)
|
|
{
|
|
LoadPalette(sLitMatchLinePalTable[matchLineId], sMatchLinePalOffsets[matchLineId], PLTT_SIZEOF(1));
|
|
}
|
|
|
|
static void DarkenMatchLine(u8 matchLineId)
|
|
{
|
|
LoadPalette(sDarkMatchLinePalTable[matchLineId], sMatchLinePalOffsets[matchLineId], PLTT_SIZEOF(1));
|
|
}
|
|
|
|
// light up the match line for each bet by the player
|
|
static void LightenBetTiles(u8 betVal)
|
|
{
|
|
u8 i;
|
|
for (i = 0; i < sMatchLinesPerBet[betVal]; i++)
|
|
LightenMatchLine(sBetToMatchLineIds[betVal][i]);
|
|
}
|
|
|
|
static void DarkenBetTiles(u8 betVal)
|
|
{
|
|
u8 i;
|
|
for (i = 0; i < sMatchLinesPerBet[betVal]; i++)
|
|
DarkenMatchLine(sBetToMatchLineIds[betVal][i]);
|
|
}
|
|
|
|
#define sMatchLineId data[0]
|
|
#define sFlashing data[1]
|
|
#define sNumFullFlashes data[2]
|
|
#define sDelayTimer data[3]
|
|
#define sColor data[4]
|
|
#define sColorIncr data[5]
|
|
#define sAtOriginalColor data[7]
|
|
|
|
// Creates invisible sprites that flash the bet lines/numbers where a match occurs
|
|
// 5 are created, 1 for each possible match line (3 rows, 2 diagonals)
|
|
static void CreateInvisibleFlashMatchLineSprites(void)
|
|
{
|
|
u8 i;
|
|
for (i = 0; i < ARRAY_COUNT(sSlotMachine->flashMatchLineSpriteIds); i++)
|
|
{
|
|
u8 spriteId = CreateInvisibleSprite(SpriteCB_FlashMatchingLines);
|
|
gSprites[spriteId].sMatchLineId = i;
|
|
sSlotMachine->flashMatchLineSpriteIds[i] = spriteId;
|
|
}
|
|
}
|
|
|
|
static void FlashMatchLine(u8 matchLineId)
|
|
{
|
|
struct Sprite *sprite = &gSprites[sSlotMachine->flashMatchLineSpriteIds[matchLineId]];
|
|
sprite->sFlashing = TRUE;
|
|
sprite->sNumFullFlashes = 4;
|
|
sprite->sDelayTimer = 0;
|
|
sprite->sColor = 0;
|
|
sprite->sColorIncr = 2;
|
|
sprite->sAtOriginalColor = FALSE;
|
|
}
|
|
|
|
// Match line flashes 4 times before the payout begins
|
|
// After this it does half-brightness flashes until the payout finishes
|
|
static bool8 IsMatchLineDoneFlashingBeforePayout(void)
|
|
{
|
|
u8 i;
|
|
for (i = 0; i < ARRAY_COUNT(sSlotMachine->flashMatchLineSpriteIds); i++)
|
|
{
|
|
struct Sprite *sprite = &gSprites[sSlotMachine->flashMatchLineSpriteIds[i]];
|
|
if (sprite->sFlashing && sprite->sNumFullFlashes)
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// When payout is finished, stop lines flashing (but not if they're in the middle of a flash)
|
|
static bool8 TryStopMatchLinesFlashing(void)
|
|
{
|
|
u8 i;
|
|
for (i = 0; i < ARRAY_COUNT(sSlotMachine->flashMatchLineSpriteIds); i++)
|
|
{
|
|
if (!TryStopMatchLineFlashing(sSlotMachine->flashMatchLineSpriteIds[i]))
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static bool8 TryStopMatchLineFlashing(u8 spriteId)
|
|
{
|
|
struct Sprite *sprite = &gSprites[spriteId];
|
|
if (!sprite->sFlashing)
|
|
return TRUE;
|
|
if (sprite->sAtOriginalColor)
|
|
sprite->sFlashing = FALSE;
|
|
|
|
return sprite->sAtOriginalColor;
|
|
}
|
|
|
|
static void SpriteCB_FlashMatchingLines(struct Sprite *sprite)
|
|
{
|
|
s16 maxColorChange;
|
|
if (sprite->sFlashing)
|
|
{
|
|
if (!sprite->sDelayTimer--)
|
|
{
|
|
sprite->sAtOriginalColor = FALSE;
|
|
sprite->sDelayTimer = 1;
|
|
sprite->sColor += sprite->sColorIncr;
|
|
maxColorChange = 4;
|
|
if (sprite->sNumFullFlashes)
|
|
maxColorChange = 8;
|
|
if (sprite->sColor <= 0)
|
|
{
|
|
// Returned to original color, reverse
|
|
sprite->sAtOriginalColor = TRUE;
|
|
sprite->sColorIncr = -sprite->sColorIncr;
|
|
if (sprite->sNumFullFlashes)
|
|
sprite->sNumFullFlashes--;
|
|
}
|
|
else if (sprite->sColor >= maxColorChange) {
|
|
// Reached peak darkness, reverse
|
|
sprite->sColorIncr = -sprite->sColorIncr;
|
|
}
|
|
if (sprite->sNumFullFlashes)
|
|
sprite->sDelayTimer <<= 1;
|
|
}
|
|
MultiplyPaletteRGBComponents(sMatchLinePalOffsets[sprite->sMatchLineId], sprite->sColor, sprite->sColor, sprite->sColor);
|
|
}
|
|
}
|
|
|
|
#undef sMatchLineId
|
|
#undef sFlashing
|
|
#undef sNumFullFlashes
|
|
#undef sDelayTimer
|
|
#undef sColor
|
|
#undef sColorIncr
|
|
#undef sAtOriginalColor
|
|
|
|
#define sDelayTimer data[1]
|
|
#define sFlashState data[2]
|
|
#define sFlashDir data[3]
|
|
|
|
static void FlashSlotMachineLights(void)
|
|
{
|
|
u8 taskId = CreateTask(Task_FlashSlotMachineLights, 6);
|
|
gTasks[taskId].sFlashDir = 1;
|
|
Task_FlashSlotMachineLights(taskId);
|
|
}
|
|
|
|
static bool8 TryStopSlotMachineLights(void)
|
|
{
|
|
u8 taskId = FindTaskIdByFunc(Task_FlashSlotMachineLights);
|
|
if (gTasks[taskId].sFlashState == 0)
|
|
{
|
|
DestroyTask(taskId);
|
|
LoadPalette(sSlotMachineMenu_Pal, BG_PLTT_ID(1), PLTT_SIZE_4BPP);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void Task_FlashSlotMachineLights(u8 taskId)
|
|
{
|
|
struct Task *task = &gTasks[taskId];
|
|
if (!task->sDelayTimer--)
|
|
{
|
|
task->sDelayTimer = 4;
|
|
task->sFlashState += task->sFlashDir;
|
|
if (task->sFlashState == 0 || task->sFlashState == 2)
|
|
task->sFlashDir = -task->sFlashDir;
|
|
}
|
|
LoadPalette(sFlashingLightsPalTable[task->sFlashState], BG_PLTT_ID(1), PLTT_SIZE_4BPP);
|
|
}
|
|
|
|
#undef sDelayTimer
|
|
#undef sFlashState
|
|
#undef sFlashDir
|
|
|
|
#define tState data[0]
|
|
#define tNumBolts data[1]
|
|
#define tSpriteId data[2]
|
|
#define tTimer data[2] // re-used
|
|
#define tAnimating data[15]
|
|
|
|
static void CreatePikaPowerBoltTask(void)
|
|
{
|
|
sSlotMachine->pikaPowerBoltTaskId = CreateTask(Task_CreatePikaPowerBolt, 8);
|
|
}
|
|
|
|
static void AddPikaPowerBolt(u8 bolts)
|
|
{
|
|
struct Task *task = &gTasks[sSlotMachine->pikaPowerBoltTaskId];
|
|
ResetPikaPowerBoltTask(task);
|
|
task->tState = PIKABOLT_TASK_ADD_BOLT;
|
|
task->tNumBolts++;
|
|
task->tAnimating = TRUE;
|
|
}
|
|
|
|
static void ResetPikaPowerBolts(void)
|
|
{
|
|
struct Task *task = &gTasks[sSlotMachine->pikaPowerBoltTaskId];
|
|
ResetPikaPowerBoltTask(task);
|
|
task->tState = PIKABOLT_TASK_CLEAR_ALL;
|
|
task->tAnimating = TRUE;
|
|
}
|
|
|
|
static bool8 IsPikaPowerBoltAnimating(void)
|
|
{
|
|
return gTasks[sSlotMachine->pikaPowerBoltTaskId].tAnimating;
|
|
}
|
|
|
|
static void Task_CreatePikaPowerBolt(u8 taskId)
|
|
{
|
|
sPikaPowerBoltTasks[gTasks[taskId].tState](&gTasks[taskId]);
|
|
}
|
|
|
|
static void PikaPowerBolt_Idle(struct Task *task)
|
|
{
|
|
}
|
|
|
|
static void PikaPowerBolt_AddBolt(struct Task *task)
|
|
{
|
|
task->tSpriteId = CreatePikaPowerBoltSprite((task->tNumBolts << 3) + 20, 20);
|
|
task->tState++; // PIKABOLT_TASK_WAIT_ANIM
|
|
}
|
|
|
|
// The bolt sprite spins around as it appears
|
|
// Once the anim is done, destroy the sprite and set the bolt in the tilemap instead
|
|
static void PikaPowerBolt_WaitAnim(struct Task *task)
|
|
{
|
|
if (gSprites[task->tSpriteId].data[7])
|
|
{
|
|
s16 r5 = task->tNumBolts + 2;
|
|
s16 r3 = 0;
|
|
s16 r2 = 0;
|
|
if (task->tNumBolts == 1)
|
|
r3 = 1, r2 = 1;
|
|
else if (task->tNumBolts == 16)
|
|
r3 = 2, r2 = 2;
|
|
sSelectedPikaPowerTile[r2] = sPikaPowerTileTable[r3][0];
|
|
LoadBgTilemap(2, &sSelectedPikaPowerTile[r2], 2, r5 + 0x40);
|
|
DestroyPikaPowerBoltSprite(task->tSpriteId);
|
|
task->tState = PIKABOLT_TASK_IDLE;
|
|
task->tAnimating = 0;
|
|
}
|
|
}
|
|
|
|
static void PikaPowerBolt_ClearAll(struct Task *task)
|
|
{
|
|
s16 r5 = task->tNumBolts + 2;
|
|
s16 r3 = 0;
|
|
s16 r2 = 3;
|
|
if (task->tNumBolts == 1)
|
|
r3 = 1, r2 = 1;
|
|
else if (task->tNumBolts == 16)
|
|
r3 = 2, r2 = 2;
|
|
if (task->tTimer == 0)
|
|
{
|
|
sSelectedPikaPowerTile[r2] = sPikaPowerTileTable[r3][1];
|
|
LoadBgTilemap(2, &sSelectedPikaPowerTile[r2], 2, r5 + 0x40);
|
|
task->tNumBolts--;
|
|
}
|
|
if (++task->tTimer >= 20)
|
|
task->tTimer = 0;
|
|
if (task->tNumBolts == 0)
|
|
{
|
|
task->tState = PIKABOLT_TASK_IDLE;
|
|
task->tAnimating = 0;
|
|
}
|
|
}
|
|
|
|
static void ResetPikaPowerBoltTask(struct Task *task)
|
|
{
|
|
u8 i;
|
|
|
|
for (i = 2; i < NUM_TASK_DATA; i++)
|
|
task->data[i] = 0;
|
|
}
|
|
|
|
static void LoadPikaPowerMeter(u8 bolts)
|
|
{
|
|
s16 i;
|
|
s16 r3 = 0, r1 = 0;
|
|
s16 r4 = 3;
|
|
for (i = 0; i < bolts; i++, r4++)
|
|
{
|
|
r3 = 0, r1 = 0;
|
|
if (i == 0)
|
|
r3 = 1, r1 = 1;
|
|
else if (i == 15) // meter is full
|
|
r3 = 2, r1 = 2;
|
|
sSelectedPikaPowerTile[r1] = sPikaPowerTileTable[r3][0];
|
|
LoadBgTilemap(2, &sSelectedPikaPowerTile[r1], 2, r4 + 0x40);
|
|
}
|
|
for (; i < 16; i++, r4++)
|
|
{
|
|
r3 = 0, r1 = 3;
|
|
if (i == 0)
|
|
r3 = 1, r1 = 1;
|
|
else if (i == 15)
|
|
r3 = 2, r1 = 2;
|
|
sSelectedPikaPowerTile[r1] = sPikaPowerTileTable[r3][1];
|
|
LoadBgTilemap(2, &sSelectedPikaPowerTile[r1], 2, r4 + 0x40);
|
|
}
|
|
gTasks[sSlotMachine->pikaPowerBoltTaskId].data[1] = bolts;
|
|
}
|
|
|
|
#undef tState
|
|
#undef tNumBolts
|
|
#undef tSpriteId
|
|
#undef tTimer
|
|
#undef tAnimating
|
|
|
|
#define tState data[0]
|
|
#define tReelSpeed data[1]
|
|
#define tTimer3 data[2]
|
|
#define tRtReelSpeed data[4]
|
|
#define tTimer2 data[4]
|
|
#define tTimer1 data[5]
|
|
#define tExplodeChecks data[6]
|
|
|
|
static void BeginReelTime(void)
|
|
{
|
|
u8 taskId = CreateTask(Task_ReelTime, 7);
|
|
Task_ReelTime(taskId);
|
|
}
|
|
|
|
static bool8 IsReelTimeTaskDone(void)
|
|
{
|
|
if (FindTaskIdByFunc(Task_ReelTime) == TAIL_SENTINEL)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
static void Task_ReelTime(u8 taskId)
|
|
{
|
|
sReelTimeTasks[gTasks[taskId].tState](&gTasks[taskId]);
|
|
}
|
|
|
|
static void ReelTime_Init(struct Task *task)
|
|
{
|
|
sSlotMachine->reelTimeSpinsLeft = 0;
|
|
sSlotMachine->reeltimePixelOffset = 0;
|
|
sSlotMachine->reeltimePosition = 0;
|
|
task->tState++; // RT_TASK_WINDOW_ENTER
|
|
task->data[1] = 0;
|
|
task->data[2] = 30;
|
|
task->tRtReelSpeed = 1280;
|
|
gSpriteCoordOffsetX = 0;
|
|
gSpriteCoordOffsetY = 0;
|
|
SetGpuReg(REG_OFFSET_BG1HOFS, 0);
|
|
SetGpuReg(REG_OFFSET_BG1VOFS, 0);
|
|
LoadReelTimeWindowTilemap(REG_OFFSET_BG3VOFS, 0);
|
|
CreateReelTimeMachineSprites();
|
|
CreateReelTimePikachuSprite();
|
|
CreateReelTimeNumberSprites();
|
|
CreateReelTimeShadowSprites();
|
|
CreateReelTimeNumberGapSprite();
|
|
GetReelTimeDraw();
|
|
StopMapMusic();
|
|
PlayNewMapMusic(MUS_ROULETTE);
|
|
}
|
|
|
|
static void ReelTime_WindowEnter(struct Task *task)
|
|
{
|
|
s16 r3;
|
|
gSpriteCoordOffsetX -= 8;
|
|
task->data[1] += 8;
|
|
r3 = ((task->data[1] + 240) & 0xff) >> 3;
|
|
SetGpuReg(REG_OFFSET_BG1HOFS, task->data[1] & 0x1ff);
|
|
if (r3 != task->data[2] && task->data[3] <= 18)
|
|
{
|
|
task->data[2] = r3;
|
|
task->data[3] = task->data[1] >> 3;
|
|
LoadReelTimeWindowTilemap(r3, task->data[3]);
|
|
}
|
|
if (task->data[1] >= 200)
|
|
{
|
|
task->tState++; // RT_TASK_WAIT_START_PIKA
|
|
task->data[3] = 0;
|
|
}
|
|
AdvanceReeltimeReel(task->tRtReelSpeed >> 8);
|
|
}
|
|
|
|
static void ReelTime_WaitStartPikachu(struct Task *task)
|
|
{
|
|
AdvanceReeltimeReel(task->tRtReelSpeed >> 8);
|
|
if (++task->tTimer1 >= 60)
|
|
{
|
|
task->tState++; // RT_TASK_PIKA_SPEEDUP1
|
|
CreateReelTimeBoltSprites();
|
|
CreateReelTimePikachuAuraSprites();
|
|
}
|
|
}
|
|
|
|
static void ReelTime_PikachuSpeedUp1(struct Task *task)
|
|
{
|
|
int i;
|
|
u8 pikachuAnimIds[ARRAY_COUNT(sReelTimePikachuAnimIds)];
|
|
s16 reelTimeBoltDelays[ARRAY_COUNT(sReelTimeBoltDelays)];
|
|
s16 pikachuAuraFlashDelays[ARRAY_COUNT(sPikachuAuraFlashDelays)];
|
|
|
|
memcpy(pikachuAnimIds, sReelTimePikachuAnimIds, sizeof(sReelTimePikachuAnimIds));
|
|
memcpy(reelTimeBoltDelays, sReelTimeBoltDelays, sizeof(sReelTimeBoltDelays));
|
|
memcpy(pikachuAuraFlashDelays, sPikachuAuraFlashDelays, sizeof(sPikachuAuraFlashDelays));
|
|
|
|
AdvanceReeltimeReel(task->tRtReelSpeed >> 8);
|
|
// gradually slow down the reel
|
|
task->tRtReelSpeed -= 4;
|
|
i = 4 - (task->tRtReelSpeed >> 8);
|
|
SetReelTimeBoltDelay(reelTimeBoltDelays[i]);
|
|
SetReelTimePikachuAuraFlashDelay(pikachuAuraFlashDelays[i]);
|
|
StartSpriteAnimIfDifferent(&gSprites[sSlotMachine->reelTimePikachuSpriteId], pikachuAnimIds[i]);
|
|
// once speed goes below 256, go to next ReelTime task and keep the speed level
|
|
if (task->tRtReelSpeed <= 0x100)
|
|
{
|
|
task->tState++; // RT_TASK_PIKA_SPEEDUP2
|
|
task->tRtReelSpeed = 0x100;
|
|
task->tTimer1 = 0;
|
|
}
|
|
}
|
|
|
|
static void ReelTime_PikachuSpeedUp2(struct Task *task)
|
|
{
|
|
AdvanceReeltimeReel(task->tRtReelSpeed >> 8);
|
|
if (++task->tTimer1 >= 80)
|
|
{
|
|
task->tState++; // RT_TASK_WAIT_REEL
|
|
task->tTimer1 = 0;
|
|
SetReelTimePikachuAuraFlashDelay(2);
|
|
StartSpriteAnimIfDifferent(&gSprites[sSlotMachine->reelTimePikachuSpriteId], 3);
|
|
}
|
|
}
|
|
|
|
static void ReelTime_WaitReel(struct Task *task)
|
|
{
|
|
AdvanceReeltimeReel(task->tRtReelSpeed >> 8);
|
|
task->tRtReelSpeed = (u8)task->tRtReelSpeed + 0x80;
|
|
if (++task->tTimer1 >= 80)
|
|
{
|
|
task->tState++; // RT_TASK_CHECK_EXPLODE
|
|
task->tTimer1 = 0;
|
|
}
|
|
}
|
|
|
|
// Check whether the ReelTime machine should explode.
|
|
//
|
|
// The ReelTime machine displays 0 when this task starts. If there is a positive
|
|
// ReelTime draw, the machine keeps spinning until it lands on that number.
|
|
//
|
|
// Otherwise, it checks every 40 frames whether it should explode. If so, it
|
|
// explodes immediately. After 4 checks, the machine won't explode but continues
|
|
// to spin until it lands on 0.
|
|
static void ReelTime_CheckExplode(struct Task *task)
|
|
{
|
|
AdvanceReeltimeReel(task->tRtReelSpeed >> 8);
|
|
task->tRtReelSpeed = (u8)task->tRtReelSpeed + 0x40;
|
|
if (++task->tTimer1 >= 40)
|
|
{
|
|
task->tTimer1 = 0;
|
|
if (sSlotMachine->reelTimeDraw)
|
|
{
|
|
if (sSlotMachine->reelTimeSpinsLeft <= task->tExplodeChecks)
|
|
task->tState++; // RT_TASK_LAND
|
|
}
|
|
else if (task->tExplodeChecks > 3)
|
|
{
|
|
task->tState++; // RT_TASK_LAND
|
|
}
|
|
else if (ShouldReelTimeMachineExplode(task->tExplodeChecks))
|
|
{
|
|
task->tState = RT_TASK_EXPLODE;
|
|
}
|
|
task->tExplodeChecks++;
|
|
}
|
|
}
|
|
|
|
// Reel spins until it lands on the selected outcome.
|
|
static void ReelTime_LandOnOutcome(struct Task *task)
|
|
{
|
|
s16 reeltimePixelOffset = sSlotMachine->reeltimePixelOffset % 20;
|
|
if (reeltimePixelOffset)
|
|
{
|
|
reeltimePixelOffset = AdvanceReeltimeReelToNextSymbol(task->tRtReelSpeed >> 8);
|
|
task->tRtReelSpeed = (u8)task->tRtReelSpeed + 0x40;
|
|
}
|
|
else if (GetReelTimeSymbol(1) != sSlotMachine->reelTimeDraw)
|
|
{
|
|
AdvanceReeltimeReel(task->tRtReelSpeed >> 8);
|
|
reeltimePixelOffset = sSlotMachine->reeltimePixelOffset % 20;
|
|
task->tRtReelSpeed = (u8)task->tRtReelSpeed + 0x40;
|
|
}
|
|
if (reeltimePixelOffset == 0 && GetReelTimeSymbol(1) == sSlotMachine->reelTimeDraw)
|
|
{
|
|
task->tRtReelSpeed = 0; // Also initializes task->tTimer2
|
|
task->tState++; // RT_TASK_PIKA_REACT
|
|
}
|
|
}
|
|
|
|
// Animate Pikachu reaction. Clear any power bolts the player may have won if
|
|
// they got a positive ReelTime draw.
|
|
static void ReelTime_PikachuReact(struct Task *task)
|
|
{
|
|
if (++task->tTimer2 >= 60)
|
|
{
|
|
StopMapMusic();
|
|
DestroyReelTimeBoltSprites();
|
|
DestroyReelTimePikachuAuraSprites();
|
|
task->tState++; // RT_TASK_WAIT_CLEAR_POWER
|
|
if(sSlotMachine->reelTimeDraw == 0)
|
|
{
|
|
task->tTimer2 = 0xa0;
|
|
StartSpriteAnimIfDifferent(&gSprites[sSlotMachine->reelTimePikachuSpriteId], 5);
|
|
PlayFanfare(MUS_TOO_BAD);
|
|
}
|
|
else
|
|
{
|
|
task->tTimer2 = 0xc0;
|
|
StartSpriteAnimIfDifferent(&gSprites[sSlotMachine->reelTimePikachuSpriteId], 4);
|
|
gSprites[sSlotMachine->reelTimePikachuSpriteId].animCmdIndex = 0;
|
|
if (sSlotMachine->pikaPowerBolts)
|
|
{
|
|
ResetPikaPowerBolts();
|
|
sSlotMachine->pikaPowerBolts = 0;
|
|
}
|
|
PlayFanfare(MUS_SLOTS_WIN);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ReelTime_WaitClearPikaPower(struct Task *task)
|
|
{
|
|
if ((task->tTimer2 == 0 || --task->tTimer2 == 0) && !IsPikaPowerBoltAnimating())
|
|
task->tState++; // RT_TASK_CLOSE_WINDOW_SUCCESS
|
|
}
|
|
|
|
static void ReelTime_CloseWindow(struct Task *task)
|
|
{
|
|
s16 r4;
|
|
gSpriteCoordOffsetX -= 8;
|
|
task->data[1] += 8;
|
|
task->data[3] += 8;
|
|
r4 = ((task->data[1] - 8) & 0xff) >> 3;
|
|
SetGpuReg(REG_OFFSET_BG1HOFS, task->data[1] & 0x1ff);
|
|
if (task->data[3] >> 3 <= 25)
|
|
ClearReelTimeWindowTilemap(r4);
|
|
else
|
|
task->tState++; // RT_TASK_DESTROY_SPRITES
|
|
}
|
|
|
|
// Destroy sprites and wrap up the ReelTime task.
|
|
//
|
|
// If the player got a positive ReelTime draw, select the speed that the slot
|
|
// reels will initially move at.
|
|
static void ReelTime_DestroySprites(struct Task *task)
|
|
{
|
|
sSlotMachine->reelTimeSpinsUsed = 0;
|
|
sSlotMachine->reelTimeSpinsLeft = sSlotMachine->reelTimeDraw;
|
|
gSpriteCoordOffsetX = 0;
|
|
SetGpuReg(REG_OFFSET_BG1HOFS, 0);
|
|
sSlotMachine->reelSpeed = REEL_NORMAL_SPEED;
|
|
DestroyReelTimePikachuSprite();
|
|
DestroyReelTimeMachineSprites();
|
|
DestroyReelTimeShadowSprites();
|
|
PlayNewMapMusic(sSlotMachine->backupMapMusic);
|
|
if (sSlotMachine->reelTimeSpinsLeft == 0)
|
|
{
|
|
DestroyTask(FindTaskIdByFunc(Task_ReelTime));
|
|
}
|
|
else
|
|
{
|
|
CreateDigitalDisplayScene(DIG_DISPLAY_REEL_TIME);
|
|
task->tReelSpeed = ReelTimeSpeed();
|
|
task->tTimer3 = 0;
|
|
task->data[3] = 0;
|
|
task->tState++; // RT_TASK_SET_REEL_SPEED
|
|
}
|
|
}
|
|
|
|
// Slow the slot reels down until they match the selected speed.
|
|
static void ReelTime_SetReelSpeed(struct Task *task)
|
|
{
|
|
if (sSlotMachine->reelSpeed == task->tReelSpeed)
|
|
task->tState++; // RT_TASK_END_SUCCESS
|
|
else if (sSlotMachine->reelPixelOffsets[0] % REEL_SYMBOL_HEIGHT == 0 && (++task->tTimer3 & 0x07) == 0)
|
|
sSlotMachine->reelSpeed >>= 1;
|
|
}
|
|
|
|
static void ReelTime_EndSuccess(struct Task *task)
|
|
{
|
|
if (IsDigitalDisplayAnimFinished())
|
|
DestroyTask(FindTaskIdByFunc(Task_ReelTime));
|
|
}
|
|
|
|
static void ReelTime_ExplodeMachine(struct Task *task)
|
|
{
|
|
DestroyReelTimeMachineSprites();
|
|
DestroyReelTimeBoltSprites();
|
|
DestroyReelTimePikachuAuraSprites();
|
|
CreateReelTimeExplosionSprite();
|
|
gSprites[sSlotMachine->reelTimeShadowSpriteIds[0]].invisible = TRUE;
|
|
StartSpriteAnimIfDifferent(&gSprites[sSlotMachine->reelTimePikachuSpriteId], 5);
|
|
task->tState++; // RT_TASK_WAIT_EXPLODE
|
|
task->data[4] = 4;
|
|
task->tTimer1 = 0;
|
|
StopMapMusic();
|
|
PlayFanfare(MUS_TOO_BAD);
|
|
PlaySE(SE_M_EXPLOSION);
|
|
}
|
|
|
|
static void ReelTime_WaitExplode(struct Task *task)
|
|
{
|
|
gSpriteCoordOffsetY = task->data[4];
|
|
SetGpuReg(REG_OFFSET_BG1VOFS, task->data[4]);
|
|
if (task->tTimer1 & 0x01)
|
|
task->data[4] = -task->data[4];
|
|
if ((++task->tTimer1 & 0x1f) == 0)
|
|
task->data[4] >>= 1;
|
|
if (task->data[4] == 0)
|
|
{
|
|
DestroyReelTimeExplosionSprite();
|
|
CreateReelTimeDuckSprites();
|
|
CreateBrokenReelTimeMachineSprite();
|
|
CreateReelTimeSmokeSprite();
|
|
gSprites[sSlotMachine->reelTimeShadowSpriteIds[0]].invisible = FALSE;
|
|
task->tState++; // RT_TASK_WAIT_SMOKE
|
|
task->tTimer1 = 0;
|
|
}
|
|
}
|
|
|
|
static void ReelTime_WaitSmoke(struct Task *task)
|
|
{
|
|
gSpriteCoordOffsetY = 0;
|
|
SetGpuReg(REG_OFFSET_BG1VOFS, 0);
|
|
if (IsReelTimeSmokeAnimFinished())
|
|
{
|
|
task->tState++; // RT_TASK_CLOSE_WINDOW_FAILURE
|
|
DestroyReelTimeSmokeSprite();
|
|
}
|
|
}
|
|
|
|
static void ReelTime_EndFailure(struct Task *task)
|
|
{
|
|
gSpriteCoordOffsetX = 0;
|
|
SetGpuReg(REG_OFFSET_BG1HOFS, 0);
|
|
PlayNewMapMusic(sSlotMachine->backupMapMusic);
|
|
DestroyReelTimePikachuSprite();
|
|
DestroyBrokenReelTimeMachineSprite();
|
|
DestroyReelTimeShadowSprites();
|
|
DestroyReelTimeDuckSprites();
|
|
DestroyTask(FindTaskIdByFunc(Task_ReelTime));
|
|
}
|
|
|
|
static void LoadReelTimeWindowTilemap(s16 a0, s16 a1)
|
|
{
|
|
s16 i;
|
|
for (i = 4; i < 15; i++)
|
|
LoadBgTilemap(1, &sReelTimeWindow_Tilemap[a1 + (i - 4) * 20], 2, 32 * i + a0);
|
|
}
|
|
|
|
static void ClearReelTimeWindowTilemap(s16 a0)
|
|
{
|
|
u8 i;
|
|
for (i = 4; i < 15; i++)
|
|
LoadBgTilemap(1, sEmptyTilemap, 2, 32 * i + a0);
|
|
}
|
|
|
|
#undef tState
|
|
#undef tReelSpeed
|
|
#undef tRtReelSpeed
|
|
#undef tTimer2
|
|
#undef tTimer1
|
|
#undef tExplodeChecks
|
|
|
|
#define tState data[0]
|
|
|
|
// Info Box is the screen shown when Select is pressed
|
|
static void OpenInfoBox(u8 digDisplayId)
|
|
{
|
|
u8 taskId = CreateTask(Task_InfoBox, 1);
|
|
gTasks[taskId].data[1] = digDisplayId;
|
|
Task_InfoBox(taskId);
|
|
}
|
|
|
|
static bool8 IsInfoBoxClosed(void)
|
|
{
|
|
if (FindTaskIdByFunc(Task_InfoBox) == TASK_NONE)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static void Task_InfoBox(u8 taskId)
|
|
{
|
|
sInfoBoxTasks[gTasks[taskId].tState](&gTasks[taskId]);
|
|
}
|
|
|
|
static void InfoBox_FadeIn(struct Task *task)
|
|
{
|
|
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB(0, 0, 0));
|
|
task->tState++;
|
|
}
|
|
|
|
static void InfoBox_WaitFade(struct Task *task)
|
|
{
|
|
if (!gPaletteFade.active)
|
|
task->tState++;
|
|
}
|
|
|
|
static void InfoBox_DrawWindow(struct Task *task)
|
|
{
|
|
DestroyDigitalDisplayScene();
|
|
LoadInfoBoxTilemap();
|
|
AddWindow(&sWindowTemplate_InfoBox);
|
|
PutWindowTilemap(1);
|
|
FillWindowPixelBuffer(1, PIXEL_FILL(0));
|
|
task->tState++;
|
|
}
|
|
|
|
static void InfoBox_AddText(struct Task *task)
|
|
{
|
|
AddTextPrinterParameterized3(1, FONT_NORMAL, 2, 5, sColors_ReeltimeHelp, 0, gText_ReelTimeHelp);
|
|
CopyWindowToVram(1, COPYWIN_FULL);
|
|
BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB(0, 0, 0));
|
|
task->tState++;
|
|
}
|
|
|
|
static void InfoBox_WaitInput(struct Task *task)
|
|
{
|
|
if (JOY_NEW(B_BUTTON | SELECT_BUTTON))
|
|
{
|
|
FillWindowPixelBuffer(1, PIXEL_FILL(0));
|
|
ClearWindowTilemap(1);
|
|
CopyWindowToVram(1, COPYWIN_MAP);
|
|
RemoveWindow(1);
|
|
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB(0, 0, 0));
|
|
task->tState++;
|
|
}
|
|
}
|
|
|
|
static void InfoBox_LoadSlotMachineTilemap(struct Task *task)
|
|
{
|
|
LoadSlotMachineMenuTilemap();
|
|
ShowBg(3);
|
|
task->tState++;
|
|
}
|
|
|
|
static void InfoBox_CreateDigitalDisplay(struct Task *task)
|
|
{
|
|
CreateDigitalDisplayScene(task->data[1]);
|
|
task->tState++;
|
|
}
|
|
|
|
static void InfoBox_LoadPikaPowerMeter(struct Task *task)
|
|
{
|
|
LoadPikaPowerMeter(sSlotMachine->pikaPowerBolts);
|
|
BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB(0, 0, 0));
|
|
task->tState++;
|
|
}
|
|
|
|
static void InfoBox_FreeTask(struct Task *task)
|
|
{
|
|
DestroyTask(FindTaskIdByFunc(Task_InfoBox));
|
|
}
|
|
|
|
#undef tState
|
|
|
|
#define sWaitForAnim data[7]
|
|
|
|
static void CreateDigitalDisplayTask(void)
|
|
{
|
|
u8 i;
|
|
struct Task *task;
|
|
i = CreateTask(Task_DigitalDisplay, 3);
|
|
sSlotMachine->digDisplayTaskId = i;
|
|
task = &gTasks[i];
|
|
task->data[1] = -1;
|
|
for (i = 4; i < NUM_TASK_DATA; i++)
|
|
task->data[i] = MAX_SPRITES;
|
|
}
|
|
|
|
// For the panel on the right side of the slot screen
|
|
static void CreateDigitalDisplayScene(u8 id)
|
|
{
|
|
u8 i;
|
|
struct Task *task;
|
|
|
|
DestroyDigitalDisplayScene();
|
|
|
|
task = &gTasks[sSlotMachine->digDisplayTaskId];
|
|
task->data[1] = id;
|
|
|
|
for (i = 0; sDigitalDisplayScenes[id][i].spriteTemplateId != 255; i++)
|
|
{
|
|
u8 spriteId;
|
|
spriteId = CreateStdDigitalDisplaySprite(
|
|
sDigitalDisplayScenes[id][i].spriteTemplateId,
|
|
sDigitalDisplayScenes[id][i].dispInfoId,
|
|
sDigitalDisplayScenes[id][i].spriteId
|
|
);
|
|
task->data[4 + i] = spriteId;
|
|
}
|
|
}
|
|
|
|
static void AddDigitalDisplaySprite(u8 templateIdx, SpriteCallback callback, s16 x, s16 y, s16 spriteId)
|
|
{
|
|
u8 i;
|
|
struct Task *task = &gTasks[sSlotMachine->digDisplayTaskId];
|
|
for (i = 4; i < NUM_TASK_DATA; i++)
|
|
{
|
|
if (task->data[i] == MAX_SPRITES)
|
|
{
|
|
task->data[i] = CreateDigitalDisplaySprite(templateIdx, callback, x, y, spriteId);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void DestroyDigitalDisplayScene(void)
|
|
{
|
|
u8 i;
|
|
struct Task *task = &gTasks[sSlotMachine->digDisplayTaskId];
|
|
|
|
if ((u16)task->data[1] != 0xFFFF)
|
|
sDigitalDisplaySceneExitCallbacks[task->data[1]]();
|
|
|
|
for (i = 4; i < NUM_TASK_DATA; i++)
|
|
{
|
|
if (task->data[i] != MAX_SPRITES)
|
|
{
|
|
DestroySprite(&gSprites[task->data[i]]);
|
|
task->data[i] = MAX_SPRITES;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool8 IsDigitalDisplayAnimFinished(void)
|
|
{
|
|
u8 i;
|
|
struct Task *task = &gTasks[sSlotMachine->digDisplayTaskId];
|
|
for (i = 4; i < NUM_TASK_DATA; i++)
|
|
{
|
|
if (task->data[i] != MAX_SPRITES)
|
|
{
|
|
if (gSprites[task->data[i]].sWaitForAnim)
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static void Task_DigitalDisplay(u8 taskId)
|
|
{
|
|
sDigitalDisplayTasks[gTasks[taskId].data[0]](&gTasks[taskId]);
|
|
}
|
|
|
|
static void DigitalDisplay_Idle(struct Task *task)
|
|
{
|
|
}
|
|
|
|
static void CreateReelSymbolSprites(void)
|
|
{
|
|
s16 i;
|
|
s16 j;
|
|
s16 x;
|
|
for (i = 0, x = 0x30; i < 3; i++, x += 0x28)
|
|
{
|
|
for (j = 0; j < 120; j += 24)
|
|
{
|
|
struct Sprite *sprite = gSprites + CreateSprite(&sSpriteTemplate_ReelSymbol, x, 0, 14);
|
|
sprite->oam.priority = 3;
|
|
sprite->data[0] = i;
|
|
sprite->data[1] = j;
|
|
sprite->data[3] = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_ReelSymbol(struct Sprite *sprite)
|
|
{
|
|
sprite->data[2] = sSlotMachine->reelPixelOffsets[sprite->data[0]] + sprite->data[1];
|
|
sprite->data[2] %= 120;
|
|
sprite->y = sSlotMachine->reelShockOffsets[sprite->data[0]] + 28 + sprite->data[2];
|
|
sprite->sheetTileStart = GetSpriteTileStartByTag(GetSymbolAtRest(sprite->data[0], sprite->data[2] / 24));
|
|
SetSpriteSheetFrameTileNum(sprite);
|
|
}
|
|
|
|
static void CreateCreditPayoutNumberSprites(void)
|
|
{
|
|
s16 i;
|
|
s16 x;
|
|
|
|
// Credit number sprite
|
|
for (x = 203, i = 1; i <= MAX_COINS; i *= 10, x -= 7)
|
|
CreateCoinNumberSprite(x, 23, FALSE, i);
|
|
|
|
// Payout number sprite
|
|
for (x = 235, i = 1; i <= MAX_COINS; i *= 10, x -= 7)
|
|
CreateCoinNumberSprite(x, 23, TRUE, i);
|
|
}
|
|
|
|
#define sIsPayout data[0]
|
|
#define sDigitMin data[1]
|
|
#define sDigitMax data[2]
|
|
#define sCurNum data[3] // Only used to determine whether the sprite has already been updated to show the correct digit
|
|
|
|
static void CreateCoinNumberSprite(s16 x, s16 y, bool8 isPayout, s16 digitMult)
|
|
{
|
|
struct Sprite *sprite = &gSprites[CreateSprite(&sSpriteTemplate_CoinNumber, x, y, 13)];
|
|
sprite->oam.priority = 2;
|
|
sprite->sIsPayout = isPayout;
|
|
sprite->sDigitMin = digitMult;
|
|
sprite->sDigitMax = digitMult * 10;
|
|
sprite->sCurNum = -1;
|
|
}
|
|
|
|
static void SpriteCB_CoinNumber(struct Sprite *sprite)
|
|
{
|
|
u16 tag = sSlotMachine->coins;
|
|
if (sprite->sIsPayout)
|
|
tag = sSlotMachine->payout;
|
|
if (sprite->sCurNum != tag)
|
|
{
|
|
// Convert total to current digit
|
|
sprite->sCurNum = tag;
|
|
tag %= (u16)sprite->sDigitMax;
|
|
tag /= (u16)sprite->sDigitMin;
|
|
|
|
tag += GFXTAG_NUM_0;
|
|
sprite->sheetTileStart = GetSpriteTileStartByTag(tag);
|
|
SetSpriteSheetFrameTileNum(sprite);
|
|
}
|
|
}
|
|
|
|
#undef sIsPayout
|
|
#undef sDigitMin
|
|
#undef sDigitMax
|
|
#undef sCurNum
|
|
|
|
static void CreateReelBackgroundSprite(void)
|
|
{
|
|
u8 spriteId = CreateSprite(&sSpriteTemplate_ReelBackground, 88, 72, 15);
|
|
gSprites[spriteId].oam.priority = 3;
|
|
SetSubspriteTables(&gSprites[spriteId], sSubspriteTable_ReelBackground);
|
|
}
|
|
|
|
static void CreateReelTimePikachuSprite(void)
|
|
{
|
|
struct SpriteTemplate spriteTemplate;
|
|
u8 spriteId;
|
|
if (sImageTable_ReelTimePikachu == NULL)
|
|
sImageTable_ReelTimePikachu = AllocZeroed(sizeof(struct SpriteFrameImage) * 5);
|
|
|
|
sImageTable_ReelTimePikachu[0].data = sReelTimeGfxPtr + (0 * 0x800);
|
|
sImageTable_ReelTimePikachu[0].size = 0x800;
|
|
sImageTable_ReelTimePikachu[1].data = sReelTimeGfxPtr + (1 * 0x800);
|
|
sImageTable_ReelTimePikachu[1].size = 0x800;
|
|
sImageTable_ReelTimePikachu[2].data = sReelTimeGfxPtr + (2 * 0x800);
|
|
sImageTable_ReelTimePikachu[2].size = 0x800;
|
|
sImageTable_ReelTimePikachu[3].data = sReelTimeGfxPtr + (3 * 0x800);
|
|
sImageTable_ReelTimePikachu[3].size = 0x800;
|
|
sImageTable_ReelTimePikachu[4].data = sReelTimeGfxPtr + (4 * 0x800);
|
|
sImageTable_ReelTimePikachu[4].size = 0x800;
|
|
|
|
spriteTemplate = sSpriteTemplate_ReelTimePikachu;
|
|
spriteTemplate.images = sImageTable_ReelTimePikachu;
|
|
spriteId = CreateSprite(&spriteTemplate, 280, 80, 1);
|
|
gSprites[spriteId].oam.priority = 1;
|
|
gSprites[spriteId].coordOffsetEnabled = TRUE;
|
|
sSlotMachine->reelTimePikachuSpriteId = spriteId;
|
|
}
|
|
|
|
static void DestroyReelTimePikachuSprite(void)
|
|
{
|
|
DestroySprite(&gSprites[sSlotMachine->reelTimePikachuSpriteId]);
|
|
TRY_FREE_AND_SET_NULL(sImageTable_ReelTimePikachu);
|
|
}
|
|
|
|
static void SpriteCB_ReelTimePikachu(struct Sprite *sprite)
|
|
{
|
|
sprite->y2 = sprite->x2 = 0;
|
|
if (sprite->animNum == 4)
|
|
{
|
|
sprite->y2 = sprite->x2 = 8;
|
|
if ((sprite->animCmdIndex != 0 && sprite->animDelayCounter != 0) || (sprite->animCmdIndex == 0 && sprite->animDelayCounter == 0))
|
|
sprite->y2 = -8;
|
|
}
|
|
}
|
|
|
|
static void CreateReelTimeMachineSprites(void)
|
|
{
|
|
struct SpriteTemplate spriteTemplate;
|
|
u8 spriteId;
|
|
struct Sprite *sprite;
|
|
|
|
if (sImageTable_ReelTimeMachineAntennae == NULL)
|
|
sImageTable_ReelTimeMachineAntennae = AllocZeroed(sizeof(struct SpriteFrameImage) * 1);
|
|
|
|
sImageTable_ReelTimeMachineAntennae[0].data = sReelTimeGfxPtr + 0x2800;
|
|
sImageTable_ReelTimeMachineAntennae[0].size = 0x300;
|
|
spriteTemplate = sSpriteTemplate_ReelTimeMachineAntennae;
|
|
spriteTemplate.images = sImageTable_ReelTimeMachineAntennae;
|
|
spriteId = CreateSprite(&spriteTemplate, 368, 52, 7);
|
|
sprite = &gSprites[spriteId];
|
|
sprite->oam.priority = 1;
|
|
sprite->coordOffsetEnabled = TRUE;
|
|
SetSubspriteTables(sprite, sSubspriteTable_ReelTimeMachineAntennae);
|
|
sSlotMachine->reelTimeMachineSpriteIds[0] = spriteId;
|
|
|
|
if (sImageTable_ReelTimeMachine == NULL)
|
|
sImageTable_ReelTimeMachine = AllocZeroed(sizeof(struct SpriteFrameImage) * 1);
|
|
|
|
sImageTable_ReelTimeMachine[0].data = sReelTimeGfxPtr + 0x2800 + 0x300;
|
|
sImageTable_ReelTimeMachine[0].size = 0x500;
|
|
spriteTemplate = sSpriteTemplate_ReelTimeMachine;
|
|
spriteTemplate.images = sImageTable_ReelTimeMachine;
|
|
spriteId = CreateSprite(&spriteTemplate, 368, 84, 7);
|
|
sprite = &gSprites[spriteId];
|
|
sprite->oam.priority = 1;
|
|
sprite->coordOffsetEnabled = TRUE;
|
|
SetSubspriteTables(sprite, sSubspriteTable_ReelTimeMachine);
|
|
sSlotMachine->reelTimeMachineSpriteIds[1] = spriteId;
|
|
}
|
|
|
|
static void CreateBrokenReelTimeMachineSprite(void)
|
|
{
|
|
struct SpriteTemplate spriteTemplate;
|
|
u8 spriteId;
|
|
struct Sprite *sprite;
|
|
|
|
if (sImageTable_BrokenReelTimeMachine == NULL)
|
|
sImageTable_BrokenReelTimeMachine = AllocZeroed(sizeof(struct SpriteFrameImage) * 1);
|
|
|
|
sImageTable_BrokenReelTimeMachine[0].data = sReelTimeGfxPtr + 0x3000;
|
|
sImageTable_BrokenReelTimeMachine[0].size = 0x600;
|
|
spriteTemplate = sSpriteTemplate_BrokenReelTimeMachine;
|
|
spriteTemplate.images = sImageTable_BrokenReelTimeMachine;
|
|
spriteId = CreateSprite(&spriteTemplate, 168 - gSpriteCoordOffsetX, 80, 7);
|
|
sprite = &gSprites[spriteId];
|
|
sprite->oam.priority = 1;
|
|
sprite->coordOffsetEnabled = TRUE;
|
|
SetSubspriteTables(sprite, sSubspriteTable_BrokenReelTimeMachine);
|
|
sSlotMachine->reelTimeBrokenMachineSpriteId = spriteId;
|
|
}
|
|
|
|
static void CreateReelTimeNumberSprites(void)
|
|
{
|
|
u8 i;
|
|
s16 r5;
|
|
for (i = 0, r5 = 0; i < ARRAY_COUNT(sSlotMachine->reelTimeNumberSpriteIds); i++, r5 += 20)
|
|
{
|
|
u8 spriteId = CreateSprite(&sSpriteTemplate_ReelTimeNumbers, 368, 0, 10);
|
|
struct Sprite *sprite = &gSprites[spriteId];
|
|
sprite->oam.priority = 1;
|
|
sprite->coordOffsetEnabled = TRUE;
|
|
sprite->data[7] = r5;
|
|
sSlotMachine->reelTimeNumberSpriteIds[i] = spriteId;
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_ReelTimeNumbers(struct Sprite *sprite)
|
|
{
|
|
s16 r0 = (u16)(sSlotMachine->reeltimePixelOffset + sprite->data[7]);
|
|
r0 %= 40;
|
|
sprite->y = r0 + 59;
|
|
StartSpriteAnimIfDifferent(sprite, GetReelTimeSymbol(r0 / 20));
|
|
}
|
|
|
|
static void CreateReelTimeShadowSprites(void)
|
|
{
|
|
u8 spriteId = CreateSprite(&sSpriteTemplate_ReelTimeShadow, 368, 100, 9);
|
|
struct Sprite *sprite = &gSprites[spriteId];
|
|
sprite->coordOffsetEnabled = TRUE;
|
|
sprite->oam.priority = 1;
|
|
SetSubspriteTables(sprite, sSubspriteTable_ReelTimeShadow);
|
|
sSlotMachine->reelTimeShadowSpriteIds[0] = spriteId;
|
|
|
|
spriteId = CreateSprite(&sSpriteTemplate_ReelTimeShadow, 288, 104, 4);
|
|
sprite = &gSprites[spriteId];
|
|
sprite->coordOffsetEnabled = TRUE;
|
|
sprite->oam.priority = 1;
|
|
SetSubspriteTables(sprite, sSubspriteTable_ReelTimeShadow);
|
|
sSlotMachine->reelTimeShadowSpriteIds[1] = spriteId;
|
|
}
|
|
|
|
// Creates a small black bar on the Reel Time machine to fill the gap between the numbers
|
|
static void CreateReelTimeNumberGapSprite(void)
|
|
{
|
|
u8 spriteId = CreateSprite(&sSpriteTemplate_ReelTimeNumberGap, 368, 76, 11);
|
|
struct Sprite *sprite = &gSprites[spriteId];
|
|
sprite->coordOffsetEnabled = TRUE;
|
|
sprite->oam.priority = 1;
|
|
SetSubspriteTables(sprite, sSubspriteTable_ReelTimeNumberGap);
|
|
sSlotMachine->reelTimeNumberGapSpriteId = spriteId;
|
|
}
|
|
|
|
static void DestroyReelTimeMachineSprites(void)
|
|
{
|
|
u8 i;
|
|
|
|
DestroySprite(&gSprites[sSlotMachine->reelTimeNumberGapSpriteId]);
|
|
for (i = 0; i < ARRAY_COUNT(sSlotMachine->reelTimeMachineSpriteIds); i++)
|
|
DestroySprite(&gSprites[sSlotMachine->reelTimeMachineSpriteIds[i]]);
|
|
|
|
TRY_FREE_AND_SET_NULL(sImageTable_ReelTimeMachineAntennae);
|
|
TRY_FREE_AND_SET_NULL(sImageTable_ReelTimeMachine);
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sSlotMachine->reelTimeNumberSpriteIds); i++)
|
|
DestroySprite(&gSprites[sSlotMachine->reelTimeNumberSpriteIds[i]]);
|
|
}
|
|
|
|
static void DestroyReelTimeShadowSprites(void)
|
|
{
|
|
u8 i;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sSlotMachine->reelTimeShadowSpriteIds); i++)
|
|
DestroySprite(&gSprites[sSlotMachine->reelTimeShadowSpriteIds[i]]);
|
|
}
|
|
|
|
static void DestroyBrokenReelTimeMachineSprite(void)
|
|
{
|
|
DestroySprite(&gSprites[sSlotMachine->reelTimeBrokenMachineSpriteId]);
|
|
TRY_FREE_AND_SET_NULL(sImageTable_BrokenReelTimeMachine);
|
|
}
|
|
|
|
#define sDelayTimer data[0]
|
|
#define sXDir data[1]
|
|
#define sYDir data[2]
|
|
#define sCounter data[3]
|
|
#define sDelay data[7]
|
|
|
|
static void CreateReelTimeBoltSprites(void)
|
|
{
|
|
u8 spriteId = CreateSprite(&sSpriteTemplate_ReelTimeBolt, 152, 32, 5);
|
|
struct Sprite *sprite = &gSprites[spriteId];
|
|
sprite->oam.priority = 1;
|
|
sprite->hFlip = TRUE;
|
|
sSlotMachine->reelTimeBoltSpriteIds[0] = spriteId;
|
|
sprite->sDelayTimer = 8;
|
|
sprite->sXDir = -1;
|
|
sprite->sYDir = -1;
|
|
sprite->sDelay = 32;
|
|
|
|
spriteId = CreateSprite(&sSpriteTemplate_ReelTimeBolt, 184, 32, 5);
|
|
sprite = &gSprites[spriteId];
|
|
sprite->oam.priority = 1;
|
|
sSlotMachine->reelTimeBoltSpriteIds[1] = spriteId;
|
|
sprite->sXDir = 1;
|
|
sprite->sYDir = -1;
|
|
sprite->sDelay = 32;
|
|
}
|
|
|
|
static void SpriteCB_ReelTimeBolt(struct Sprite *sprite)
|
|
{
|
|
if (sprite->sDelayTimer != 0)
|
|
{
|
|
sprite->sDelayTimer--;
|
|
sprite->x2 = 0;
|
|
sprite->y2 = 0;
|
|
sprite->invisible = TRUE;
|
|
}
|
|
else
|
|
{
|
|
sprite->invisible = FALSE;
|
|
sprite->x2 += sprite->sXDir;
|
|
sprite->y2 += sprite->sYDir;
|
|
if (++sprite->sCounter >= 8)
|
|
{
|
|
sprite->sDelayTimer = sprite->sDelay;
|
|
sprite->sCounter = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void SetReelTimeBoltDelay(s16 delay)
|
|
{
|
|
gSprites[sSlotMachine->reelTimeBoltSpriteIds[0]].sDelay = delay;
|
|
gSprites[sSlotMachine->reelTimeBoltSpriteIds[1]].sDelay = delay;
|
|
}
|
|
|
|
static void DestroyReelTimeBoltSprites(void)
|
|
{
|
|
u8 i;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sSlotMachine->reelTimeBoltSpriteIds); i++)
|
|
DestroySprite(&gSprites[sSlotMachine->reelTimeBoltSpriteIds[i]]);
|
|
}
|
|
|
|
#undef sDelayTimer
|
|
#undef sXDir
|
|
#undef sYDir
|
|
#undef sCounter
|
|
#undef sDelay
|
|
|
|
#define sFlashPal data[0]
|
|
#define sColorIdx data[5]
|
|
#define sDelayTimer data[6]
|
|
#define sDelay data[7]
|
|
|
|
static void CreateReelTimePikachuAuraSprites(void)
|
|
{
|
|
// Left half of electricity orb
|
|
u8 spriteId = CreateSprite(&sSpriteTemplate_ReelTimePikachuAura, 72, 80, 3);
|
|
gSprites[spriteId].oam.priority = 1;
|
|
gSprites[spriteId].sFlashPal = TRUE; // Only one of them needs to do the flashing, they share the palette
|
|
gSprites[spriteId].sColorIdx = 0;
|
|
gSprites[spriteId].sDelayTimer = 16;
|
|
gSprites[spriteId].sDelay = 8;
|
|
sSlotMachine->reelTimePikachuAuraSpriteIds[0] = spriteId;
|
|
|
|
// Right half
|
|
spriteId = CreateSprite(&sSpriteTemplate_ReelTimePikachuAura, 104, 80, 3);
|
|
gSprites[spriteId].oam.priority = 1;
|
|
gSprites[spriteId].hFlip = TRUE;
|
|
sSlotMachine->reelTimePikachuAuraSpriteIds[1] = spriteId;
|
|
}
|
|
|
|
static void SpriteCB_ReelTimePikachuAura(struct Sprite *sprite)
|
|
{
|
|
u8 colors[] = {16, 0};
|
|
if (sprite->sFlashPal && --sprite->sDelayTimer <= 0)
|
|
{
|
|
MultiplyInvertedPaletteRGBComponents((IndexOfSpritePaletteTag(PALTAG_PIKA_AURA) << 4) + 0x103, colors[sprite->sColorIdx], colors[sprite->sColorIdx], colors[sprite->sColorIdx]);
|
|
++sprite->sColorIdx;
|
|
sprite->sColorIdx &= 1;
|
|
sprite->sDelayTimer = sprite->sDelay;
|
|
}
|
|
}
|
|
|
|
static void SetReelTimePikachuAuraFlashDelay(s16 delay)
|
|
{
|
|
gSprites[sSlotMachine->reelTimePikachuAuraSpriteIds[0]].sDelay = delay;
|
|
}
|
|
|
|
static void DestroyReelTimePikachuAuraSprites(void)
|
|
{
|
|
u8 i;
|
|
MultiplyInvertedPaletteRGBComponents((IndexOfSpritePaletteTag(PALTAG_PIKA_AURA) << 4) + 0x103, 0, 0, 0);
|
|
for (i = 0; i < ARRAY_COUNT(sSlotMachine->reelTimePikachuAuraSpriteIds); i++)
|
|
DestroySprite(&gSprites[sSlotMachine->reelTimePikachuAuraSpriteIds[i]]);
|
|
}
|
|
|
|
#undef sFlashPal
|
|
#undef sColorIdx
|
|
#undef sDelayTimer
|
|
#undef sDelay
|
|
|
|
static void CreateReelTimeExplosionSprite(void)
|
|
{
|
|
u8 spriteId = CreateSprite(&sSpriteTemplate_ReelTimeExplosion, 168, 80, 6);
|
|
gSprites[spriteId].oam.priority = 1;
|
|
sSlotMachine->reelTimeExplosionSpriteId = spriteId;
|
|
}
|
|
|
|
static void SpriteCB_ReelTimeExplosion(struct Sprite *sprite)
|
|
{
|
|
sprite->y2 = gSpriteCoordOffsetY;
|
|
}
|
|
|
|
static void DestroyReelTimeExplosionSprite(void)
|
|
{
|
|
DestroySprite(&gSprites[sSlotMachine->reelTimeExplosionSpriteId]);
|
|
}
|
|
|
|
// The "confusion" ducks that circle Pikachu if the Reel Time machine explodes
|
|
static void CreateReelTimeDuckSprites(void)
|
|
{
|
|
u8 i;
|
|
u16 sp[] = {0x0, 0x40, 0x80, 0xC0};
|
|
for (i = 0; i < ARRAY_COUNT(sSlotMachine->reelTimeDuckSpriteIds); i++)
|
|
{
|
|
u8 spriteId = CreateSprite(&sSpriteTemplate_ReelTimeDuck, 80 - gSpriteCoordOffsetX, 68, 0);
|
|
struct Sprite *sprite = &gSprites[spriteId];
|
|
sprite->oam.priority = 1;
|
|
sprite->coordOffsetEnabled = TRUE;
|
|
sprite->data[0] = sp[i];
|
|
sSlotMachine->reelTimeDuckSpriteIds[i] = spriteId;
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_ReelTimeDuck(struct Sprite *sprite)
|
|
{
|
|
sprite->data[0] -= 2;
|
|
sprite->data[0] &= 0xff;
|
|
sprite->x2 = Cos(sprite->data[0], 20);
|
|
sprite->y2 = Sin(sprite->data[0], 6);
|
|
sprite->subpriority = 0;
|
|
if (sprite->data[0] >= 0x80)
|
|
{
|
|
sprite->subpriority = 2;
|
|
}
|
|
if (++sprite->data[1] >= 16)
|
|
{
|
|
sprite->hFlip ^= 1;
|
|
sprite->data[1] = 0;
|
|
}
|
|
}
|
|
|
|
static void DestroyReelTimeDuckSprites(void)
|
|
{
|
|
u8 i;
|
|
for (i = 0; i < ARRAY_COUNT(sSlotMachine->reelTimeDuckSpriteIds); i++)
|
|
{
|
|
DestroySprite(&gSprites[sSlotMachine->reelTimeDuckSpriteIds[i]]);
|
|
}
|
|
}
|
|
|
|
#define sState data[0]
|
|
#define sMoveY data[1]
|
|
#define sTimer data[2]
|
|
#define sAnimFinished data[7]
|
|
|
|
static void CreateReelTimeSmokeSprite(void)
|
|
{
|
|
u8 spriteId = CreateSprite(&sSpriteTemplate_ReelTimeSmoke, 168, 60, 8);
|
|
struct Sprite *sprite = &gSprites[spriteId];
|
|
sprite->oam.priority = 1;
|
|
sprite->oam.affineMode = ST_OAM_AFFINE_DOUBLE;
|
|
InitSpriteAffineAnim(sprite);
|
|
sSlotMachine->reelTimeSmokeSpriteId = spriteId;
|
|
}
|
|
|
|
static void SpriteCB_ReelTimeSmoke(struct Sprite *sprite)
|
|
{
|
|
if (sprite->sState == 0)
|
|
{
|
|
if (sprite->affineAnimEnded)
|
|
sprite->sState++;
|
|
}
|
|
else if (sprite->sState == 1)
|
|
{
|
|
sprite->invisible ^= 1;
|
|
if (++sprite->sTimer >= 24)
|
|
{
|
|
sprite->sState++;
|
|
sprite->sTimer = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprite->invisible = TRUE;
|
|
if (++sprite->sTimer >= 16)
|
|
sprite->sAnimFinished = TRUE;
|
|
}
|
|
sprite->sMoveY &= 0xff;
|
|
sprite->sMoveY += 16;
|
|
sprite->y2 -= (sprite->sMoveY >> 8);
|
|
}
|
|
|
|
static u8 IsReelTimeSmokeAnimFinished(void)
|
|
{
|
|
return gSprites[sSlotMachine->reelTimeSmokeSpriteId].sAnimFinished;
|
|
}
|
|
|
|
static void DestroyReelTimeSmokeSprite(void)
|
|
{
|
|
struct Sprite *sprite = &gSprites[sSlotMachine->reelTimeSmokeSpriteId];
|
|
FreeOamMatrix(sprite->oam.matrixNum);
|
|
DestroySprite(sprite);
|
|
}
|
|
|
|
#undef sState
|
|
#undef sMoveY
|
|
#undef sTimer
|
|
#undef sAnimFinished
|
|
|
|
static u8 CreatePikaPowerBoltSprite(s16 x, s16 y)
|
|
{
|
|
u8 spriteId = CreateSprite(&sSpriteTemplate_PikaPowerBolt, x, y, 12);
|
|
struct Sprite *sprite = &gSprites[spriteId];
|
|
sprite->oam.priority = 2;
|
|
sprite->oam.affineMode = ST_OAM_AFFINE_DOUBLE;
|
|
InitSpriteAffineAnim(sprite);
|
|
return spriteId;
|
|
}
|
|
|
|
static void SpriteCB_PikaPowerBolt(struct Sprite *sprite)
|
|
{
|
|
if (sprite->affineAnimEnded)
|
|
sprite->data[7] = TRUE;
|
|
}
|
|
|
|
static void DestroyPikaPowerBoltSprite(u8 spriteId)
|
|
{
|
|
struct Sprite *sprite = &gSprites[spriteId];
|
|
FreeOamMatrix(sprite->oam.matrixNum);
|
|
DestroySprite(sprite);
|
|
}
|
|
|
|
static u8 CreateStdDigitalDisplaySprite(u8 templateIdx, u8 dispInfoId, s16 spriteId)
|
|
{
|
|
return CreateDigitalDisplaySprite(templateIdx, sDigitalDisplay_SpriteCallbacks[dispInfoId], sDigitalDisplay_SpriteCoords[dispInfoId][0], sDigitalDisplay_SpriteCoords[dispInfoId][1], spriteId);
|
|
}
|
|
|
|
#define sState data[0]
|
|
#define sCounter data[1]
|
|
#define sSpriteId data[6]
|
|
|
|
static u8 CreateDigitalDisplaySprite(u8 templateIdx, SpriteCallback callback, s16 x, s16 y, s16 internalSpriteId)
|
|
{
|
|
struct SpriteTemplate spriteTemplate;
|
|
u8 spriteId;
|
|
struct Sprite *sprite;
|
|
|
|
spriteTemplate = *sSpriteTemplates_DigitalDisplay[templateIdx];
|
|
spriteTemplate.images = sImageTables_DigitalDisplay[templateIdx];
|
|
spriteId = CreateSprite(&spriteTemplate, x, y, 16);
|
|
sprite = &gSprites[spriteId];
|
|
sprite->oam.priority = 3;
|
|
sprite->callback = callback;
|
|
sprite->sSpriteId = internalSpriteId;
|
|
sprite->sWaitForAnim = TRUE;
|
|
if (sSubspriteTables_DigitalDisplay[templateIdx])
|
|
SetSubspriteTables(sprite, sSubspriteTables_DigitalDisplay[templateIdx]);
|
|
return spriteId;
|
|
}
|
|
|
|
static void SpriteCB_DigitalDisplay_Static(struct Sprite *sprite)
|
|
{
|
|
sprite->sWaitForAnim = FALSE;
|
|
}
|
|
|
|
static void SpriteCB_DigitalDisplay_Smoke(struct Sprite *sprite)
|
|
{
|
|
s16 targetX[] = {4, -4, 4, -4};
|
|
s16 targetY[] = {4, 4, -4, -4};
|
|
|
|
if (sprite->sCounter++ >= 16)
|
|
{
|
|
sprite->subspriteTableNum ^= 1;
|
|
sprite->sCounter = 0;
|
|
}
|
|
sprite->x2 = 0;
|
|
sprite->y2 = 0;
|
|
if (sprite->subspriteTableNum != 0)
|
|
{
|
|
sprite->x2 = targetX[sprite->sSpriteId];
|
|
sprite->y2 = targetY[sprite->sSpriteId];
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_DigitalDisplay_SmokeNE(struct Sprite *sprite)
|
|
{
|
|
sprite->hFlip = TRUE;
|
|
SpriteCB_DigitalDisplay_Smoke(sprite);
|
|
}
|
|
|
|
static void SpriteCB_DigitalDisplay_SmokeSW(struct Sprite *sprite)
|
|
{
|
|
sprite->vFlip = TRUE;
|
|
SpriteCB_DigitalDisplay_Smoke(sprite);
|
|
}
|
|
|
|
static void SpriteCB_DigitalDisplay_SmokeSE(struct Sprite *sprite)
|
|
{
|
|
sprite->hFlip = TRUE;
|
|
sprite->vFlip = TRUE;
|
|
SpriteCB_DigitalDisplay_Smoke(sprite);
|
|
}
|
|
|
|
// The word "Reel" in Reel Time
|
|
static void SpriteCB_DigitalDisplay_Reel(struct Sprite *sprite)
|
|
{
|
|
switch (sprite->sState)
|
|
{
|
|
case 0:
|
|
sprite->x += 4;
|
|
if (sprite->x >= 0xd0)
|
|
{
|
|
sprite->x = 0xd0;
|
|
sprite->sState++;
|
|
}
|
|
break;
|
|
case 1:
|
|
if (++sprite->sCounter > 90)
|
|
sprite->sState++;
|
|
break;
|
|
case 2:
|
|
sprite->x += 4;
|
|
if (sprite->x >= 0x110)
|
|
sprite->sState++;
|
|
break;
|
|
case 3:
|
|
sprite->sWaitForAnim = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// The word "Time" in Reel Time
|
|
static void SpriteCB_DigitalDisplay_Time(struct Sprite *sprite)
|
|
{
|
|
switch (sprite->sState)
|
|
{
|
|
case 0:
|
|
sprite->x -= 4;
|
|
if (sprite->x <= 0xd0)
|
|
{
|
|
sprite->x = 0xd0;
|
|
sprite->sState++;
|
|
}
|
|
break;
|
|
case 1:
|
|
if (++sprite->sCounter > 90)
|
|
sprite->sState++;
|
|
break;
|
|
case 2:
|
|
sprite->x -= 4;
|
|
if (sprite->x <= 0x90)
|
|
sprite->sState++;
|
|
break;
|
|
case 3:
|
|
sprite->sWaitForAnim = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_DigitalDisplay_ReelTimeNumber(struct Sprite *sprite)
|
|
{
|
|
switch (sprite->sState)
|
|
{
|
|
case 0:
|
|
StartSpriteAnim(sprite, sSlotMachine->reelTimeSpinsLeft - 1);
|
|
sprite->sState++;
|
|
// fallthrough
|
|
case 1:
|
|
if (++sprite->sCounter >= 4)
|
|
{
|
|
sprite->sState++;
|
|
sprite->sCounter = 0;
|
|
}
|
|
break;
|
|
case 2:
|
|
sprite->x += 4;
|
|
if (sprite->x >= 0xd0)
|
|
{
|
|
sprite->x = 0xd0;
|
|
sprite->sState++;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (++sprite->sCounter > 90)
|
|
sprite->sState++;
|
|
break;
|
|
case 4:
|
|
sprite->x += 4;
|
|
if (sprite->x >= 0xf8)
|
|
sprite->sState++;
|
|
break;
|
|
case 5:
|
|
sprite->sWaitForAnim = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_DigitalDisplay_PokeballRocking(struct Sprite *sprite)
|
|
{
|
|
switch (sprite->sState)
|
|
{
|
|
case 0:
|
|
sprite->animPaused = TRUE;
|
|
sprite->sState++;
|
|
// fallthrough
|
|
case 1:
|
|
sprite->y += 8;
|
|
if (sprite->y >= 0x70)
|
|
{
|
|
sprite->y = 0x70;
|
|
sprite->sCounter = 16;
|
|
sprite->sState++;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (sprite->data[2] == 0)
|
|
{
|
|
sprite->y -= sprite->sCounter;
|
|
sprite->sCounter = -sprite->sCounter;
|
|
if (++sprite->data[3] >= 2)
|
|
{
|
|
sprite->sCounter >>= 2;
|
|
sprite->data[3] = 0;
|
|
if (sprite->sCounter == 0)
|
|
{
|
|
sprite->sState++;
|
|
sprite->sWaitForAnim = FALSE;
|
|
sprite->animPaused = FALSE;
|
|
}
|
|
}
|
|
}
|
|
sprite->data[2]++;
|
|
sprite->data[2] &= 0x07;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_DigitalDisplay_Stop(struct Sprite *sprite)
|
|
{
|
|
switch (sprite->sState)
|
|
{
|
|
case 0:
|
|
if (++sprite->sCounter > 8)
|
|
sprite->sState++;
|
|
break;
|
|
case 1:
|
|
sprite->y += 2;
|
|
if (sprite->y >= 0x30)
|
|
{
|
|
sprite->y = 0x30;
|
|
sprite->sState++;
|
|
sprite->sWaitForAnim = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_DigitalDisplay_AButtonStop(struct Sprite *sprite)
|
|
{
|
|
switch (sprite->sState)
|
|
{
|
|
case 0:
|
|
sprite->invisible = TRUE;
|
|
if (++sprite->sCounter > 0x20)
|
|
{
|
|
sprite->sState++;
|
|
sprite->sCounter = 5;
|
|
sprite->oam.mosaic = TRUE;
|
|
sprite->invisible = FALSE;
|
|
StartSpriteAnim(sprite, 1);
|
|
SetGpuReg(REG_OFFSET_MOSAIC, ((sprite->sCounter << 4) | sprite->sCounter) << 8);
|
|
}
|
|
break;
|
|
case 1:
|
|
sprite->sCounter -= (sprite->data[2] >> 8);
|
|
if (sprite->sCounter < 0)
|
|
sprite->sCounter = 0;
|
|
SetGpuReg(REG_OFFSET_MOSAIC, ((sprite->sCounter << 4) | sprite->sCounter) << 8);
|
|
sprite->data[2] &= 0xff;
|
|
sprite->data[2] += 0x80;
|
|
if (sprite->sCounter == 0)
|
|
{
|
|
sprite->sState++;
|
|
sprite->sWaitForAnim = FALSE;
|
|
sprite->oam.mosaic = FALSE;
|
|
StartSpriteAnim(sprite, 0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_DigitalDisplay_PokeballShining(struct Sprite *sprite)
|
|
{
|
|
if (sprite->sCounter < 3)
|
|
{
|
|
LoadPalette(sPokeballShiningPalTable[sprite->sCounter], OBJ_PLTT_ID(IndexOfSpritePaletteTag(PALTAG_DIG_DISPLAY)), PLTT_SIZE_4BPP);
|
|
if (++sprite->data[2] >= 4)
|
|
{
|
|
sprite->data[1]++;
|
|
sprite->data[2] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LoadPalette(sPokeballShiningPalTable[sprite->sCounter], OBJ_PLTT_ID(IndexOfSpritePaletteTag(PALTAG_DIG_DISPLAY)), PLTT_SIZE_4BPP);
|
|
if (++sprite->data[2] >= 25)
|
|
{
|
|
sprite->sCounter = 0;
|
|
sprite->data[2] = 0;
|
|
}
|
|
}
|
|
StartSpriteAnimIfDifferent(sprite, 1);
|
|
sprite->sWaitForAnim = FALSE;
|
|
}
|
|
|
|
static void SpriteCB_DigitalDisplay_RegBonus(struct Sprite *sprite)
|
|
{
|
|
// Elements in array correspond to R E G B O N U S
|
|
s16 letterXOffset[] = { 0, -40, 0, 0, 48, 0, 24, 0};
|
|
s16 letterYOffset[] = {-32, 0, -32, -48, 0, -48, 0, -48};
|
|
s16 letterDelay[] = { 16, 12, 16, 0, 0, 4, 8, 8};
|
|
|
|
switch (sprite->sState)
|
|
{
|
|
case 0:
|
|
sprite->x2 = letterXOffset[sprite->sSpriteId];
|
|
sprite->y2 = letterYOffset[sprite->sSpriteId];
|
|
sprite->sCounter = letterDelay[sprite->sSpriteId];
|
|
sprite->sState++;
|
|
// fallthrough
|
|
case 1:
|
|
if (sprite->sCounter-- == 0)
|
|
sprite->sState++;
|
|
break;
|
|
case 2:
|
|
if (sprite->x2 > 0)
|
|
sprite->x2 -= 4;
|
|
else if (sprite->x2 < 0)
|
|
sprite->x2 += 4;
|
|
|
|
if (sprite->y2 > 0)
|
|
sprite->y2 -= 4;
|
|
else if (sprite->y2 < 0)
|
|
sprite->y2 += 4;
|
|
|
|
if (sprite->x2 == 0 && sprite->y2 == 0)
|
|
sprite->sState++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_DigitalDisplay_BigBonus(struct Sprite *sprite)
|
|
{
|
|
s16 sp0[] = {160, 192, 224, 104, 80, 64, 48, 24};
|
|
|
|
if (sprite->sState == 0)
|
|
{
|
|
sprite->sState++;
|
|
sprite->sCounter = 12;
|
|
}
|
|
sprite->x2 = Cos(sp0[sprite->sSpriteId], sprite->sCounter);
|
|
sprite->y2 = Sin(sp0[sprite->sSpriteId], sprite->sCounter);
|
|
if (sprite->sCounter != 0)
|
|
sprite->sCounter--;
|
|
}
|
|
|
|
// For the A Button prompt when inserting bet
|
|
// Initially no sprite until after the first bet
|
|
static void SpriteCB_DigitalDisplay_AButtonStart(struct Sprite *sprite)
|
|
{
|
|
switch (sprite->sState)
|
|
{
|
|
case 0:
|
|
sSlotMachine->winIn = WININ_WIN0_BG_ALL | WININ_WIN0_CLR;
|
|
sSlotMachine->winOut = WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR;
|
|
sSlotMachine->win0v = WIN_RANGE(32, 136);
|
|
sprite->invisible = TRUE;
|
|
sprite->sState++;
|
|
// fallthrough
|
|
case 1:
|
|
sprite->sCounter += 2;
|
|
sprite->data[2] = sprite->sCounter + 176;
|
|
sprite->data[3] = DISPLAY_WIDTH - sprite->sCounter;
|
|
if (sprite->data[2] > 208)
|
|
sprite->data[2] = 208;
|
|
if (sprite->data[3] < 208)
|
|
sprite->data[3] = 208;
|
|
sSlotMachine->win0h = (sprite->data[2] << 8) | sprite->data[3];
|
|
if (sprite->sCounter > 51)
|
|
{
|
|
sprite->sState++;
|
|
sSlotMachine->winIn = WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (sSlotMachine->bet == 0)
|
|
break;
|
|
AddDigitalDisplaySprite(DIG_SPRITE_A_BUTTON, SpriteCallbackDummy, 208, 116, 0);
|
|
sSlotMachine->win0h = WIN_RANGE(192, 224);
|
|
sSlotMachine->win0v = WIN_RANGE(104, 128);
|
|
sSlotMachine->winIn = WININ_WIN0_BG_ALL | WININ_WIN0_CLR;
|
|
sprite->sState++;
|
|
sprite->sCounter = 0;
|
|
// fallthrough
|
|
case 3:
|
|
sprite->sCounter += 2;
|
|
sprite->data[2] = sprite->sCounter + 192;
|
|
sprite->data[3] = DISPLAY_WIDTH - 16 - sprite->sCounter;
|
|
if (sprite->data[2] > 208)
|
|
sprite->data[2] = 208;
|
|
if (sprite->data[3] < 208)
|
|
sprite->data[3] = 208;
|
|
sSlotMachine->win0h = (sprite->data[2] << 8) | sprite->data[3];
|
|
if (sprite->sCounter > 15)
|
|
{
|
|
sprite->sState++;
|
|
sSlotMachine->winIn = WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void EndDigitalDisplayScene_Dummy(void)
|
|
{
|
|
}
|
|
|
|
static void EndDigitalDisplayScene_StopReel(void)
|
|
{
|
|
SetGpuReg(REG_OFFSET_MOSAIC, 0);
|
|
}
|
|
|
|
static void EndDigitalDisplayScene_Win(void)
|
|
{
|
|
LoadPalette(sDigitalDisplay_Pal, OBJ_PLTT_ID(IndexOfSpritePaletteTag(PALTAG_DIG_DISPLAY)), PLTT_SIZE_4BPP);
|
|
}
|
|
|
|
static void EndDigitalDisplayScene_InsertBet(void)
|
|
{
|
|
sSlotMachine->win0h = DISPLAY_WIDTH;
|
|
sSlotMachine->win0v = DISPLAY_HEIGHT;
|
|
sSlotMachine->winIn = WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR;
|
|
sSlotMachine->winOut = WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR;
|
|
}
|
|
|
|
static void LoadSlotMachineGfx(void)
|
|
{
|
|
u8 i;
|
|
|
|
LoadReelBackground();
|
|
sDigitalDisplayGfxPtr = Alloc(0x3200);
|
|
LZDecompressWram(gSlotMachineDigitalDisplay_Gfx, sDigitalDisplayGfxPtr);
|
|
sReelTimeGfxPtr = Alloc(0x3600);
|
|
LZDecompressWram(sReelTimeGfx, sReelTimeGfxPtr);
|
|
sSlotMachineSpritesheetsPtr = AllocZeroed(sizeof(struct SpriteSheet) * ARRAY_COUNT(sSlotMachineSpriteSheets));
|
|
for (i = 0; i < ARRAY_COUNT(sSlotMachineSpriteSheets); i++)
|
|
{
|
|
sSlotMachineSpritesheetsPtr[i].data = sSlotMachineSpriteSheets[i].data;
|
|
sSlotMachineSpritesheetsPtr[i].size = sSlotMachineSpriteSheets[i].size;
|
|
sSlotMachineSpritesheetsPtr[i].tag = sSlotMachineSpriteSheets[i].tag;
|
|
}
|
|
sSlotMachineSpritesheetsPtr[GFXTAG_STOP - 1].data = sDigitalDisplayGfxPtr + 0xA00;
|
|
sSlotMachineSpritesheetsPtr[GFXTAG_BONUS - 1].data = sDigitalDisplayGfxPtr + 0x1400;
|
|
sSlotMachineSpritesheetsPtr[GFXTAG_BIG - 1].data = sDigitalDisplayGfxPtr + 0x1600;
|
|
sSlotMachineSpritesheetsPtr[GFXTAG_REG - 1].data = sDigitalDisplayGfxPtr + 0x1900;
|
|
LoadSpriteSheets(sSlotMachineSpritesheetsPtr);
|
|
LoadSpritePalettes(sSlotMachineSpritePalettes);
|
|
}
|
|
|
|
static void LoadReelBackground(void)
|
|
{
|
|
u8 *dest;
|
|
u8 i, j;
|
|
|
|
sReelBackgroundSpriteSheet = AllocZeroed(sizeof(struct SpriteSheet));
|
|
sReelBackground_Gfx = AllocZeroed(0x2000); // Background is plain white
|
|
dest = sReelBackground_Gfx;
|
|
for (i = 0; i < 0x40; i++)
|
|
{
|
|
for (j = 0; j < 0x20; j++, dest++)
|
|
*dest = sReelBackground_Tilemap[j];
|
|
}
|
|
sReelBackgroundSpriteSheet->data = sReelBackground_Gfx;
|
|
sReelBackgroundSpriteSheet->size = 0x800;
|
|
sReelBackgroundSpriteSheet->tag = GFXTAG_REEL_BG;
|
|
LoadSpriteSheet(sReelBackgroundSpriteSheet);
|
|
}
|
|
|
|
static void LoadMenuGfx(void)
|
|
{
|
|
sMenuGfx = Alloc(0x2200);
|
|
LZDecompressWram(gSlotMachineMenu_Gfx, sMenuGfx);
|
|
LoadBgTiles(2, sMenuGfx, 0x2200, 0);
|
|
LoadPalette(gSlotMachineMenu_Pal, BG_PLTT_ID(0), 5 * PLTT_SIZE_4BPP);
|
|
LoadPalette(sUnkPalette, BG_PLTT_ID(13), PLTT_SIZE_4BPP);
|
|
}
|
|
|
|
static void LoadMenuAndReelOverlayTilemaps(void)
|
|
{
|
|
LoadSlotMachineMenuTilemap();
|
|
LoadSlotMachineReelOverlay();
|
|
}
|
|
|
|
static void LoadSlotMachineMenuTilemap(void)
|
|
{
|
|
LoadBgTilemap(2, gSlotMachineMenu_Tilemap, 0x500, 0);
|
|
}
|
|
|
|
static void LoadSlotMachineReelOverlay(void)
|
|
{
|
|
s16 x, y, dx;
|
|
|
|
for (x = 4; x < 18; x += 5)
|
|
{
|
|
for (dx = 0; dx < 4; dx++)
|
|
{
|
|
LoadBgTilemap(3, sReelOverlay_Tilemap, 2, x + dx + 5 * 32);
|
|
LoadBgTilemap(3, sReelOverlay_Tilemap + 1, 2, x + dx + 13 * 32);
|
|
LoadBgTilemap(3, sReelOverlay_Tilemap + 2, 2, x + dx + 6 * 32);
|
|
LoadBgTilemap(3, sReelOverlay_Tilemap + 3, 2, x + dx + 12 * 32);
|
|
}
|
|
|
|
LoadBgTilemap(3, sReelOverlay_Tilemap + 4, 2, x + 6 * 32);
|
|
LoadBgTilemap(3, sReelOverlay_Tilemap + 5, 2, x + 12 * 32);
|
|
|
|
for (y = 7; y <= 11; y++)
|
|
LoadBgTilemap(3, sReelOverlay_Tilemap + 6, 2, x + y * 32);
|
|
}
|
|
}
|
|
|
|
// For (un)shading the gray button at the bottom of a reel when A is pressed. The button is colored in quadrants
|
|
static void SetReelButtonTilemap(s16 offset, u16 topLeft, u16 topRight, u16 bottomLeft, u16 bottomRight)
|
|
{
|
|
sReelButtonPress_Tilemap[0] = topLeft;
|
|
sReelButtonPress_Tilemap[1] = topRight;
|
|
sReelButtonPress_Tilemap[2] = bottomLeft;
|
|
sReelButtonPress_Tilemap[3] = bottomRight;
|
|
|
|
LoadBgTilemap(2, sReelButtonPress_Tilemap, 2, 15 * 32 + offset); // Top left
|
|
LoadBgTilemap(2, sReelButtonPress_Tilemap + 1, 2, 15 * 32 + 1 + offset); // Top right
|
|
LoadBgTilemap(2, sReelButtonPress_Tilemap + 2, 2, 16 * 32 + offset); // Bottom left
|
|
LoadBgTilemap(2, sReelButtonPress_Tilemap + 3, 2, 16 * 32 + 1 + offset); // Bottom Right
|
|
}
|
|
|
|
static void LoadInfoBoxTilemap(void)
|
|
{
|
|
LoadBgTilemap(2, gSlotMachineInfoBox_Tilemap, 0x500, 0);
|
|
HideBg(3);
|
|
}
|
|
|
|
static void SetDigitalDisplayImagePtrs(void)
|
|
{
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_REEL] = sImageTable_DigitalDisplay_Reel;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_TIME] = sImageTable_DigitalDisplay_Time;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_INSERT] = sImageTable_DigitalDisplay_Insert;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_WIN] = sImageTable_DigitalDisplay_Win;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_LOSE] = sImageTable_DigitalDisplay_Lose;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_A_BUTTON] = sImageTable_DigitalDisplay_AButton;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_SMOKE] = sImageTable_DigitalDisplay_Smoke;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_NUMBER] = sImageTable_DigitalDisplay_Number;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_POKE_BALL] = sImageTable_DigitalDisplay_Pokeball;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_D_PAD] = sImageTable_DigitalDisplay_DPad;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_STOP_S] = sImageTable_DigitalDisplay_Stop;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_STOP_T] = sImageTable_DigitalDisplay_Stop;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_STOP_O] = sImageTable_DigitalDisplay_Stop;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_STOP_P] = sImageTable_DigitalDisplay_Stop;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_BONUS_B] = sImageTable_DigitalDisplay_Bonus;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_BONUS_O] = sImageTable_DigitalDisplay_Bonus;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_BONUS_N] = sImageTable_DigitalDisplay_Bonus;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_BONUS_U] = sImageTable_DigitalDisplay_Bonus;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_BONUS_S] = sImageTable_DigitalDisplay_Bonus;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_BIG_B] = sImageTable_DigitalDisplay_Big;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_BIG_I] = sImageTable_DigitalDisplay_Big;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_BIG_G] = sImageTable_DigitalDisplay_Big;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_REG_R] = sImageTable_DigitalDisplay_Reg;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_REG_E] = sImageTable_DigitalDisplay_Reg;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_REG_G] = sImageTable_DigitalDisplay_Reg;
|
|
sImageTables_DigitalDisplay[DIG_SPRITE_EMPTY] = NULL;
|
|
}
|
|
|
|
static void AllocDigitalDisplayGfx(void)
|
|
{
|
|
sImageTable_DigitalDisplay_Reel = AllocZeroed(sizeof(struct SpriteFrameImage) * 1);
|
|
sImageTable_DigitalDisplay_Reel[0].data = sDigitalDisplayGfxPtr;
|
|
sImageTable_DigitalDisplay_Reel[0].size = 0x600;
|
|
|
|
sImageTable_DigitalDisplay_Time = AllocZeroed(sizeof(struct SpriteFrameImage) * 1);
|
|
sImageTable_DigitalDisplay_Time[0].data = sDigitalDisplayGfxPtr + 0x600;
|
|
sImageTable_DigitalDisplay_Time[0].size = 0x200;
|
|
|
|
sImageTable_DigitalDisplay_Insert = AllocZeroed(sizeof(struct SpriteFrameImage) * 1);
|
|
sImageTable_DigitalDisplay_Insert[0].data = sDigitalDisplayGfxPtr + 0x800;
|
|
sImageTable_DigitalDisplay_Insert[0].size = 0x200;
|
|
|
|
sImageTable_DigitalDisplay_Stop = AllocZeroed(sizeof(struct SpriteFrameImage) * 1);
|
|
sImageTable_DigitalDisplay_Stop[0].data = sDigitalDisplayGfxPtr + 0xA00;
|
|
sImageTable_DigitalDisplay_Stop[0].size = 0x200;
|
|
|
|
sImageTable_DigitalDisplay_Win = AllocZeroed(sizeof(struct SpriteFrameImage) * 1);
|
|
sImageTable_DigitalDisplay_Win[0].data = sDigitalDisplayGfxPtr + 0xC00;
|
|
sImageTable_DigitalDisplay_Win[0].size = 0x300;
|
|
|
|
sImageTable_DigitalDisplay_Lose = AllocZeroed(sizeof(struct SpriteFrameImage) * 1);
|
|
sImageTable_DigitalDisplay_Lose[0].data = sDigitalDisplayGfxPtr + 0x1000;
|
|
sImageTable_DigitalDisplay_Lose[0].size = 0x400;
|
|
|
|
sImageTable_DigitalDisplay_Bonus = AllocZeroed(sizeof(struct SpriteFrameImage) * 1);
|
|
sImageTable_DigitalDisplay_Bonus[0].data = sDigitalDisplayGfxPtr + 0x1400;
|
|
sImageTable_DigitalDisplay_Bonus[0].size = 0x200;
|
|
|
|
sImageTable_DigitalDisplay_Big = AllocZeroed(sizeof(struct SpriteFrameImage) * 1);
|
|
sImageTable_DigitalDisplay_Big[0].data = sDigitalDisplayGfxPtr + 0x1600;
|
|
sImageTable_DigitalDisplay_Big[0].size = 0x300;
|
|
|
|
sImageTable_DigitalDisplay_Reg = AllocZeroed(sizeof(struct SpriteFrameImage) * 1);
|
|
sImageTable_DigitalDisplay_Reg[0].data = sDigitalDisplayGfxPtr + 0x1900;
|
|
sImageTable_DigitalDisplay_Reg[0].size = 0x300;
|
|
|
|
sImageTable_DigitalDisplay_AButton = AllocZeroed(sizeof(struct SpriteFrameImage) * 2);
|
|
sImageTable_DigitalDisplay_AButton[0].data = sDigitalDisplayGfxPtr + 0x1C00;
|
|
sImageTable_DigitalDisplay_AButton[0].size = 0x200;
|
|
sImageTable_DigitalDisplay_AButton[1].data = sDigitalDisplayGfxPtr + 0x1E00;
|
|
sImageTable_DigitalDisplay_AButton[1].size = 0x200;
|
|
|
|
sImageTable_DigitalDisplay_Smoke = AllocZeroed(sizeof(struct SpriteFrameImage) * 1);
|
|
sImageTable_DigitalDisplay_Smoke[0].data = sDigitalDisplayGfxPtr + 0x2000;
|
|
sImageTable_DigitalDisplay_Smoke[0].size = 640;
|
|
|
|
sImageTable_DigitalDisplay_Number = AllocZeroed(sizeof(struct SpriteFrameImage) * 5);
|
|
sImageTable_DigitalDisplay_Number[0].data = sDigitalDisplayGfxPtr + 0x2280;
|
|
sImageTable_DigitalDisplay_Number[0].size = 0x80;
|
|
sImageTable_DigitalDisplay_Number[1].data = sDigitalDisplayGfxPtr + 0x2300;
|
|
sImageTable_DigitalDisplay_Number[1].size = 0x80;
|
|
sImageTable_DigitalDisplay_Number[2].data = sDigitalDisplayGfxPtr + 0x2380;
|
|
sImageTable_DigitalDisplay_Number[2].size = 0x80;
|
|
sImageTable_DigitalDisplay_Number[3].data = sDigitalDisplayGfxPtr + 0x2400;
|
|
sImageTable_DigitalDisplay_Number[3].size = 0x80;
|
|
sImageTable_DigitalDisplay_Number[4].data = sDigitalDisplayGfxPtr + 0x2480;
|
|
sImageTable_DigitalDisplay_Number[4].size = 0x80;
|
|
|
|
sImageTable_DigitalDisplay_Pokeball = AllocZeroed(sizeof(struct SpriteFrameImage) * 2);
|
|
sImageTable_DigitalDisplay_Pokeball[0].data = sDigitalDisplayGfxPtr + 0x2600;
|
|
sImageTable_DigitalDisplay_Pokeball[0].size = 0x480;
|
|
sImageTable_DigitalDisplay_Pokeball[1].data = sDigitalDisplayGfxPtr + 10880;
|
|
sImageTable_DigitalDisplay_Pokeball[1].size = 0x480;
|
|
|
|
sImageTable_DigitalDisplay_DPad = AllocZeroed(sizeof(struct SpriteFrameImage) * 2);
|
|
sImageTable_DigitalDisplay_DPad[0].data = sDigitalDisplayGfxPtr + 0x2F00;
|
|
sImageTable_DigitalDisplay_DPad[0].size = 0x180;
|
|
sImageTable_DigitalDisplay_DPad[1].data = sDigitalDisplayGfxPtr + 0x3080;
|
|
sImageTable_DigitalDisplay_DPad[1].size = 0x180;
|
|
}
|
|
|
|
static const u8 sReelSymbols[NUM_REELS][SYMBOLS_PER_REEL] =
|
|
{
|
|
[LEFT_REEL] = {
|
|
SYMBOL_7_RED,
|
|
SYMBOL_CHERRY,
|
|
SYMBOL_AZURILL,
|
|
SYMBOL_REPLAY,
|
|
SYMBOL_POWER,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_7_BLUE,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_CHERRY,
|
|
SYMBOL_POWER,
|
|
SYMBOL_REPLAY,
|
|
SYMBOL_AZURILL,
|
|
SYMBOL_7_RED,
|
|
SYMBOL_POWER,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_REPLAY,
|
|
SYMBOL_AZURILL,
|
|
SYMBOL_7_BLUE,
|
|
SYMBOL_POWER,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_REPLAY
|
|
},
|
|
[MIDDLE_REEL] = {
|
|
SYMBOL_7_RED,
|
|
SYMBOL_CHERRY,
|
|
SYMBOL_REPLAY,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_AZURILL,
|
|
SYMBOL_CHERRY,
|
|
SYMBOL_REPLAY,
|
|
SYMBOL_POWER,
|
|
SYMBOL_POWER,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_7_BLUE,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_REPLAY,
|
|
SYMBOL_CHERRY,
|
|
SYMBOL_AZURILL,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_REPLAY,
|
|
SYMBOL_CHERRY,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_REPLAY,
|
|
SYMBOL_CHERRY
|
|
},
|
|
[RIGHT_REEL] = {
|
|
SYMBOL_7_RED,
|
|
SYMBOL_POWER,
|
|
SYMBOL_7_BLUE,
|
|
SYMBOL_REPLAY,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_AZURILL,
|
|
SYMBOL_REPLAY,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_POWER,
|
|
SYMBOL_AZURILL,
|
|
SYMBOL_REPLAY,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_AZURILL,
|
|
SYMBOL_POWER,
|
|
SYMBOL_REPLAY,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_AZURILL,
|
|
SYMBOL_POWER,
|
|
SYMBOL_REPLAY,
|
|
SYMBOL_LOTAD,
|
|
SYMBOL_CHERRY
|
|
},
|
|
};
|
|
|
|
static const u8 sReelTimeSymbols[] = {
|
|
1, 0, 5, 4, 3, 2
|
|
};
|
|
|
|
// Column 0: Normal game
|
|
// Column 1: Lucky game
|
|
static const s16 sInitialReelPositions[NUM_REELS][2] = {
|
|
[LEFT_REEL] = {0, 6},
|
|
[MIDDLE_REEL] = {0, 10},
|
|
[RIGHT_REEL] = {0, 2}
|
|
};
|
|
|
|
static const u8 sSpecialDrawOdds[NUM_SLOT_MACHINE_IDS][MAX_BET] = {
|
|
[SLOT_MACHINE_UNLUCKIEST] = {1, 1, 12},
|
|
[SLOT_MACHINE_UNLUCKIER] = {1, 1, 14},
|
|
[SLOT_MACHINE_UNLUCKY] = {2, 2, 14},
|
|
[SLOT_MACHINE_LUCKY] = {2, 2, 14},
|
|
[SLOT_MACHINE_LUCKIER] = {2, 3, 16},
|
|
[SLOT_MACHINE_LUCKIEST] = {3, 3, 16}
|
|
};
|
|
|
|
static const u8 sBiasProbabilities_Special[][NUM_SLOT_MACHINE_IDS] = {
|
|
{
|
|
// Probabilities for BIAS_STRAIGHT_7
|
|
[SLOT_MACHINE_UNLUCKIEST] = 25,
|
|
[SLOT_MACHINE_UNLUCKIER] = 25,
|
|
[SLOT_MACHINE_UNLUCKY] = 30,
|
|
[SLOT_MACHINE_LUCKY] = 40,
|
|
[SLOT_MACHINE_LUCKIER] = 40,
|
|
[SLOT_MACHINE_LUCKIEST] = 50
|
|
},
|
|
{
|
|
// Probabilities for BIAS_REELTIME
|
|
[SLOT_MACHINE_UNLUCKIEST] = 25,
|
|
[SLOT_MACHINE_UNLUCKIER] = 25,
|
|
[SLOT_MACHINE_UNLUCKY] = 30,
|
|
[SLOT_MACHINE_LUCKY] = 30,
|
|
[SLOT_MACHINE_LUCKIER] = 35,
|
|
[SLOT_MACHINE_LUCKIEST] = 35
|
|
},
|
|
{
|
|
// Probabilities for BIAS_MIXED_7
|
|
[SLOT_MACHINE_UNLUCKIEST] = 25,
|
|
[SLOT_MACHINE_UNLUCKIER] = 25,
|
|
[SLOT_MACHINE_UNLUCKY] = 30,
|
|
[SLOT_MACHINE_LUCKY] = 25,
|
|
[SLOT_MACHINE_LUCKIER] = 25,
|
|
[SLOT_MACHINE_LUCKIEST] = 30
|
|
}
|
|
};
|
|
|
|
static const u8 sBiasProbabilities_Regular[][NUM_SLOT_MACHINE_IDS] = {
|
|
{
|
|
// Probabilities for BIAS_POWER
|
|
[SLOT_MACHINE_UNLUCKIEST] = 20,
|
|
[SLOT_MACHINE_UNLUCKIER] = 25,
|
|
[SLOT_MACHINE_UNLUCKY] = 25,
|
|
[SLOT_MACHINE_LUCKY] = 20,
|
|
[SLOT_MACHINE_LUCKIER] = 25,
|
|
[SLOT_MACHINE_LUCKIEST] = 25
|
|
},
|
|
{
|
|
// Probabilities for BIAS_AZURILL
|
|
[SLOT_MACHINE_UNLUCKIEST] = 12,
|
|
[SLOT_MACHINE_UNLUCKIER] = 15,
|
|
[SLOT_MACHINE_UNLUCKY] = 15,
|
|
[SLOT_MACHINE_LUCKY] = 18,
|
|
[SLOT_MACHINE_LUCKIER] = 19,
|
|
[SLOT_MACHINE_LUCKIEST] = 22
|
|
},
|
|
{
|
|
// Probabilities for BIAS_LOTAD
|
|
[SLOT_MACHINE_UNLUCKIEST] = 25,
|
|
[SLOT_MACHINE_UNLUCKIER] = 25,
|
|
[SLOT_MACHINE_UNLUCKY] = 25,
|
|
[SLOT_MACHINE_LUCKY] = 30,
|
|
[SLOT_MACHINE_LUCKIER] = 30,
|
|
[SLOT_MACHINE_LUCKIEST] = 40
|
|
},
|
|
{
|
|
// Probabilities for BIAS_CHERRY
|
|
[SLOT_MACHINE_UNLUCKIEST] = 25,
|
|
[SLOT_MACHINE_UNLUCKIER] = 25,
|
|
[SLOT_MACHINE_UNLUCKY] = 20,
|
|
[SLOT_MACHINE_LUCKY] = 20,
|
|
[SLOT_MACHINE_LUCKIER] = 15,
|
|
[SLOT_MACHINE_LUCKIEST] = 15
|
|
},
|
|
{
|
|
// Probabilities for BIAS_REPLAY
|
|
[SLOT_MACHINE_UNLUCKIEST] = 40,
|
|
[SLOT_MACHINE_UNLUCKIER] = 40,
|
|
[SLOT_MACHINE_UNLUCKY] = 35,
|
|
[SLOT_MACHINE_LUCKY] = 35,
|
|
[SLOT_MACHINE_LUCKIER] = 40,
|
|
[SLOT_MACHINE_LUCKIEST] = 40
|
|
}
|
|
};
|
|
|
|
// INTENTION:
|
|
// As you get more Power bolts, the odds of getting higher yields (3+ spins)
|
|
// increases modestly. There's a high chance of getting at least 1 spin, which
|
|
// will clear your Power bolts.
|
|
//
|
|
// NOTE: The way these probabilities are drawn significantly skews the odds
|
|
// toward drawing 0 spins:
|
|
//
|
|
// | Up to N bolts | Prob intended | Prob actual |
|
|
// |---------------|---------------|-------------|
|
|
// | 2 | 94% | 99% |
|
|
// | 6 | 31% | 57% |
|
|
// | 12 | 16% | 44% |
|
|
// | 15 | 2% | 31% |
|
|
// | 16 | 2% | 31% |
|
|
static const u8 sReelTimeProbabilities_NormalGame[][17] = {
|
|
{243, 243, 243, 80, 80, 80, 80, 40, 40, 40, 40, 40, 40, 5, 5, 5, 5}, // 0 spins
|
|
{ 5, 5, 5, 150, 150, 150, 150, 130, 130, 130, 130, 130, 130, 100, 100, 100, 5}, // 1 spin
|
|
{ 4, 4, 4, 20, 20, 20, 20, 80, 80, 80, 80, 80, 80, 100, 100, 100, 40}, // 2 spins
|
|
{ 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 45, 45, 45, 100}, // 3 spins
|
|
{ 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 100}, // 4 spins
|
|
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6} // 5 spins
|
|
};
|
|
|
|
// INTENTION:
|
|
// As you get more Power bolts, the odds of getting higher yields (3+ spins)
|
|
// increases substantially. There is always a high chance of getting no spins,
|
|
// which lets you keep your Power bolts.
|
|
//
|
|
// NOTE: The way these probabilities are drawn significantly skews the odds
|
|
// toward drawing 0 spins:
|
|
//
|
|
// | Up to N bolts | Prob intended | Prob actual |
|
|
// |---------------|---------------|-------------|
|
|
// | 2 | 94% | 99% |
|
|
// | 6 | 78% | 96% |
|
|
// | 12 | 63% | 88% |
|
|
// | 15 | 27% | 58% |
|
|
// | 16 | 2% | 33% |
|
|
static const u8 sReelTimeProbabilities_LuckyGame[][17] = {
|
|
{ 243, 243, 243, 200, 200, 200, 200, 160, 160, 160, 160, 160, 160, 70, 70, 70, 5}, // 0 spins
|
|
{ 5, 5, 5, 25, 25, 25, 25, 5, 5, 5, 5, 5, 5, 2, 2, 2, 6}, // 1 spin
|
|
{ 4, 4, 4, 25, 25, 25, 25, 30, 30, 30, 30, 30, 30, 40, 40, 40, 35}, // 2 spins
|
|
{ 2, 2, 2, 3, 3, 3, 3, 30, 30, 30, 30, 30, 30, 100, 100, 100, 50}, // 3 spins
|
|
{ 1, 1, 1, 2, 2, 2, 2, 30, 30, 30, 30, 30, 30, 40, 40, 40, 100}, // 4 spins
|
|
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 60} // 5 spins
|
|
};
|
|
|
|
static const u16 sReelTimeExplodeProbability[] = {
|
|
128, 175, 200, 225, 256
|
|
};
|
|
|
|
// Column 0: Probability of half-speed
|
|
// Column 1: Base probability of quarter-speed
|
|
static const u16 sReelTimeSpeed_Probabilities[][2] = {
|
|
{10, 5},
|
|
{10, 10},
|
|
{10, 15},
|
|
{10, 25},
|
|
{10, 35}
|
|
};
|
|
|
|
// Boosted odds of quarter speed during ReelTime
|
|
static const u16 sQuarterSpeed_ProbabilityBoost[] = {
|
|
0, 5, 10, 15, 20
|
|
};
|
|
|
|
static const u8 sBiasSymbols[] = {
|
|
SYMBOL_REPLAY, // BIAS_REPLAY
|
|
SYMBOL_CHERRY, // BIAS_CHERRY
|
|
SYMBOL_LOTAD, // BIAS_LOTAD
|
|
SYMBOL_AZURILL, // BIAS_AZURILL
|
|
SYMBOL_POWER, // BIAS_POWER
|
|
SYMBOL_7_RED, // BIAS_REELTIME
|
|
SYMBOL_7_RED, // BIAS_MIXED_7
|
|
SYMBOL_7_RED // BIAS_STRAIGHT_7
|
|
};
|
|
|
|
static const u16 sBiasesSpecial[] = {
|
|
BIAS_STRAIGHT_7, BIAS_REELTIME, BIAS_MIXED_7
|
|
};
|
|
|
|
static const u16 sBiasesRegular[] = {
|
|
BIAS_POWER, BIAS_AZURILL, BIAS_LOTAD, BIAS_CHERRY, BIAS_REPLAY
|
|
};
|
|
|
|
static const u8 sSymbolToMatch[] = {
|
|
[SYMBOL_7_RED] = MATCH_RED_7,
|
|
[SYMBOL_7_BLUE] = MATCH_BLUE_7,
|
|
[SYMBOL_AZURILL] = MATCH_AZURILL,
|
|
[SYMBOL_LOTAD] = MATCH_LOTAD,
|
|
[SYMBOL_CHERRY] = MATCH_CHERRY,
|
|
[SYMBOL_POWER] = MATCH_POWER,
|
|
[SYMBOL_REPLAY] = MATCH_REPLAY
|
|
};
|
|
|
|
static const u16 sSlotMatchFlags[] = {
|
|
[MATCH_CHERRY] = 1 << MATCH_CHERRY,
|
|
[MATCH_TOPBOT_CHERRY] = 1 << MATCH_TOPBOT_CHERRY,
|
|
[MATCH_REPLAY] = 1 << MATCH_REPLAY,
|
|
[MATCH_LOTAD] = 1 << MATCH_LOTAD,
|
|
[MATCH_AZURILL] = 1 << MATCH_AZURILL,
|
|
[MATCH_POWER] = 1 << MATCH_POWER,
|
|
[MATCH_MIXED_7] = 1 << MATCH_MIXED_7,
|
|
[MATCH_RED_7] = 1 << MATCH_RED_7,
|
|
[MATCH_BLUE_7] = 1 << MATCH_BLUE_7
|
|
};
|
|
|
|
static const u16 sSlotPayouts[] = {
|
|
[MATCH_CHERRY] = 2,
|
|
[MATCH_TOPBOT_CHERRY] = 4,
|
|
[MATCH_REPLAY] = 0,
|
|
[MATCH_LOTAD] = 6,
|
|
[MATCH_AZURILL] = 12,
|
|
[MATCH_POWER] = 3,
|
|
[MATCH_MIXED_7] = 90,
|
|
[MATCH_RED_7] = 300,
|
|
[MATCH_BLUE_7] = 300
|
|
};
|
|
|
|
static const s16 sDigitalDisplay_SpriteCoords[][2] = {
|
|
[DIG_DISPINFO_INSERT] = { 208, 56},
|
|
[DIG_DISPINFO_STOP_S] = { 184, 0},
|
|
[DIG_DISPINFO_STOP_T] = { 200, 8},
|
|
[DIG_DISPINFO_STOP_O] = { 216, 16},
|
|
[DIG_DISPINFO_STOP_P] = { 232, 24},
|
|
[DIG_DISPINFO_A_BUTTON_STOP] = { 208, 72},
|
|
[DIG_DISPINFO_POKE_BALL_ROCKING] = { 208, 8},
|
|
[DIG_DISPINFO_WIN] = { 208, 64},
|
|
[DIG_DISPINFO_LOSE] = { 208, 56},
|
|
[DIG_DISPINFO_SMOKE_NW] = { 192, 88},
|
|
[DIG_DISPINFO_SMOKE_NE] = { 224, 88},
|
|
[DIG_DISPINFO_SMOKE_SW] = { 192, 120},
|
|
[DIG_DISPINFO_SMOKE_SE] = { 224, 120},
|
|
[DIG_DISPINFO_REEL] = { 144, 56},
|
|
[DIG_DISPINFO_TIME] = { 272, 88},
|
|
[DIG_DISPINFO_NUMBER] = { 168, 112},
|
|
[DIG_DISPINFO_DPAD] = { 208, 84},
|
|
[DIG_DISPINFO_POKE_BALL_SHINING] = { 208, 112},
|
|
[DIG_DISPINFO_REG_R] = { 188, 52},
|
|
[DIG_DISPINFO_REG_E] = { 208, 52},
|
|
[DIG_DISPINFO_REG_G] = { 228, 52},
|
|
[DIG_DISPINFO_REG_BONUS_B] = { 184, 72},
|
|
[DIG_DISPINFO_REG_BONUS_O] = { 196, 72},
|
|
[DIG_DISPINFO_REG_BONUS_N] = { 208, 72},
|
|
[DIG_DISPINFO_REG_BONUS_U] = { 220, 72},
|
|
[DIG_DISPINFO_REG_BONUS_S] = { 232, 72},
|
|
[DIG_DISPINFO_BIG_B] = { 188, 52},
|
|
[DIG_DISPINFO_BIG_I] = { 208, 52},
|
|
[DIG_DISPINFO_BIG_G] = { 228, 52},
|
|
[DIG_DISPINFO_BIG_BONUS_B] = { 184, 72},
|
|
[DIG_DISPINFO_BIG_BONUS_O] = { 196, 72},
|
|
[DIG_DISPINFO_BIG_BONUS_N] = { 208, 72},
|
|
[DIG_DISPINFO_BIG_BONUS_U] = { 220, 72},
|
|
[DIG_DISPINFO_BIG_BONUS_S] = { 232, 72},
|
|
[DIG_DISPINFO_A_BUTTON_START] = { 0, 0} // Initially offscreen
|
|
};
|
|
|
|
static const SpriteCallback sDigitalDisplay_SpriteCallbacks[] = {
|
|
[DIG_DISPINFO_INSERT] = SpriteCB_DigitalDisplay_Static,
|
|
[DIG_DISPINFO_STOP_S] = SpriteCB_DigitalDisplay_Stop,
|
|
[DIG_DISPINFO_STOP_T] = SpriteCB_DigitalDisplay_Stop,
|
|
[DIG_DISPINFO_STOP_O] = SpriteCB_DigitalDisplay_Stop,
|
|
[DIG_DISPINFO_STOP_P] = SpriteCB_DigitalDisplay_Stop,
|
|
[DIG_DISPINFO_A_BUTTON_STOP] = SpriteCB_DigitalDisplay_AButtonStop,
|
|
[DIG_DISPINFO_POKE_BALL_ROCKING] = SpriteCB_DigitalDisplay_PokeballRocking,
|
|
[DIG_DISPINFO_WIN] = SpriteCB_DigitalDisplay_Static,
|
|
[DIG_DISPINFO_LOSE] = SpriteCB_DigitalDisplay_Static,
|
|
[DIG_DISPINFO_SMOKE_NW] = SpriteCB_DigitalDisplay_Smoke,
|
|
[DIG_DISPINFO_SMOKE_NE] = SpriteCB_DigitalDisplay_SmokeNE,
|
|
[DIG_DISPINFO_SMOKE_SW] = SpriteCB_DigitalDisplay_SmokeSW,
|
|
[DIG_DISPINFO_SMOKE_SE] = SpriteCB_DigitalDisplay_SmokeSE,
|
|
[DIG_DISPINFO_REEL] = SpriteCB_DigitalDisplay_Reel,
|
|
[DIG_DISPINFO_TIME] = SpriteCB_DigitalDisplay_Time,
|
|
[DIG_DISPINFO_NUMBER] = SpriteCB_DigitalDisplay_ReelTimeNumber,
|
|
[DIG_DISPINFO_DPAD] = SpriteCB_DigitalDisplay_Static,
|
|
[DIG_DISPINFO_POKE_BALL_SHINING] = SpriteCB_DigitalDisplay_PokeballShining,
|
|
[DIG_DISPINFO_REG_R] = SpriteCB_DigitalDisplay_RegBonus,
|
|
[DIG_DISPINFO_REG_E] = SpriteCB_DigitalDisplay_RegBonus,
|
|
[DIG_DISPINFO_REG_G] = SpriteCB_DigitalDisplay_RegBonus,
|
|
[DIG_DISPINFO_REG_BONUS_B] = SpriteCB_DigitalDisplay_RegBonus,
|
|
[DIG_DISPINFO_REG_BONUS_O] = SpriteCB_DigitalDisplay_RegBonus,
|
|
[DIG_DISPINFO_REG_BONUS_N] = SpriteCB_DigitalDisplay_RegBonus,
|
|
[DIG_DISPINFO_REG_BONUS_U] = SpriteCB_DigitalDisplay_RegBonus,
|
|
[DIG_DISPINFO_REG_BONUS_S] = SpriteCB_DigitalDisplay_RegBonus,
|
|
[DIG_DISPINFO_BIG_B] = SpriteCB_DigitalDisplay_BigBonus,
|
|
[DIG_DISPINFO_BIG_I] = SpriteCB_DigitalDisplay_BigBonus,
|
|
[DIG_DISPINFO_BIG_G] = SpriteCB_DigitalDisplay_BigBonus,
|
|
[DIG_DISPINFO_BIG_BONUS_B] = SpriteCB_DigitalDisplay_BigBonus,
|
|
[DIG_DISPINFO_BIG_BONUS_O] = SpriteCB_DigitalDisplay_BigBonus,
|
|
[DIG_DISPINFO_BIG_BONUS_N] = SpriteCB_DigitalDisplay_BigBonus,
|
|
[DIG_DISPINFO_BIG_BONUS_U] = SpriteCB_DigitalDisplay_BigBonus,
|
|
[DIG_DISPINFO_BIG_BONUS_S] = SpriteCB_DigitalDisplay_BigBonus,
|
|
[DIG_DISPINFO_A_BUTTON_START] = SpriteCB_DigitalDisplay_AButtonStart
|
|
};
|
|
|
|
static const struct DigitalDisplaySprite sDigitalDisplay_InsertBet[] = {
|
|
{DIG_SPRITE_EMPTY, DIG_DISPINFO_A_BUTTON_START, 0}, // Sprite replaced with DIG_SPRITE_A_BUTTON after first bet
|
|
{DIG_SPRITE_INSERT, DIG_DISPINFO_INSERT, 0},
|
|
{DIG_SPRITE_D_PAD, DIG_DISPINFO_DPAD, 0},
|
|
DIG_SPRITE_DUMMY
|
|
};
|
|
|
|
static const struct DigitalDisplaySprite sDigitalDisplay_StopReel[] = {
|
|
{DIG_SPRITE_STOP_S, DIG_DISPINFO_STOP_S, 0},
|
|
{DIG_SPRITE_STOP_T, DIG_DISPINFO_STOP_T, 0},
|
|
{DIG_SPRITE_STOP_O, DIG_DISPINFO_STOP_O, 0},
|
|
{DIG_SPRITE_STOP_P, DIG_DISPINFO_STOP_P, 0},
|
|
{DIG_SPRITE_A_BUTTON, DIG_DISPINFO_A_BUTTON_STOP, 0},
|
|
{DIG_SPRITE_POKE_BALL, DIG_DISPINFO_POKE_BALL_ROCKING, 0},
|
|
DIG_SPRITE_DUMMY
|
|
};
|
|
|
|
static const struct DigitalDisplaySprite sDigitalDisplay_Win[] = {
|
|
{DIG_SPRITE_WIN, DIG_DISPINFO_WIN, 0},
|
|
{DIG_SPRITE_POKE_BALL, DIG_DISPINFO_POKE_BALL_SHINING, 0},
|
|
DIG_SPRITE_DUMMY
|
|
};
|
|
|
|
static const struct DigitalDisplaySprite sDigitalDisplay_Lose[] = {
|
|
{DIG_SPRITE_LOSE, DIG_DISPINFO_LOSE, 0},
|
|
{DIG_SPRITE_SMOKE, DIG_DISPINFO_SMOKE_NW, 0},
|
|
{DIG_SPRITE_SMOKE, DIG_DISPINFO_SMOKE_NE, 1},
|
|
{DIG_SPRITE_SMOKE, DIG_DISPINFO_SMOKE_SW, 2},
|
|
{DIG_SPRITE_SMOKE, DIG_DISPINFO_SMOKE_SE, 3},
|
|
DIG_SPRITE_DUMMY
|
|
};
|
|
|
|
static const struct DigitalDisplaySprite sDigitalDisplay_ReelTime[] = {
|
|
{DIG_SPRITE_REEL, DIG_DISPINFO_REEL, 0},
|
|
{DIG_SPRITE_TIME, DIG_DISPINFO_TIME, 0},
|
|
{DIG_SPRITE_NUMBER, DIG_DISPINFO_NUMBER, 0}, // Number of reel time spins left
|
|
DIG_SPRITE_DUMMY
|
|
};
|
|
|
|
static const struct DigitalDisplaySprite sDigitalDisplay_BonusBig[] = {
|
|
{DIG_SPRITE_BIG_B, DIG_DISPINFO_BIG_B, 0},
|
|
{DIG_SPRITE_BIG_I, DIG_DISPINFO_BIG_I, 1},
|
|
{DIG_SPRITE_BIG_G, DIG_DISPINFO_BIG_G, 2},
|
|
{DIG_SPRITE_BONUS_B, DIG_DISPINFO_BIG_BONUS_B, 3},
|
|
{DIG_SPRITE_BONUS_O, DIG_DISPINFO_BIG_BONUS_O, 4},
|
|
{DIG_SPRITE_BONUS_N, DIG_DISPINFO_BIG_BONUS_N, 5},
|
|
{DIG_SPRITE_BONUS_U, DIG_DISPINFO_BIG_BONUS_U, 6},
|
|
{DIG_SPRITE_BONUS_S, DIG_DISPINFO_BIG_BONUS_S, 7},
|
|
{DIG_SPRITE_POKE_BALL, DIG_DISPINFO_POKE_BALL_SHINING, 0},
|
|
DIG_SPRITE_DUMMY
|
|
};
|
|
|
|
static const struct DigitalDisplaySprite sDigitalDisplay_BonusRegular[] = {
|
|
{DIG_SPRITE_REG_R, DIG_DISPINFO_REG_R, 0},
|
|
{DIG_SPRITE_REG_E, DIG_DISPINFO_REG_E, 1},
|
|
{DIG_SPRITE_REG_G, DIG_DISPINFO_REG_G, 2},
|
|
{DIG_SPRITE_BONUS_B, DIG_DISPINFO_REG_BONUS_B, 3},
|
|
{DIG_SPRITE_BONUS_O, DIG_DISPINFO_REG_BONUS_O, 4},
|
|
{DIG_SPRITE_BONUS_N, DIG_DISPINFO_REG_BONUS_N, 5},
|
|
{DIG_SPRITE_BONUS_U, DIG_DISPINFO_REG_BONUS_U, 6},
|
|
{DIG_SPRITE_BONUS_S, DIG_DISPINFO_REG_BONUS_S, 7},
|
|
{DIG_SPRITE_POKE_BALL, DIG_DISPINFO_POKE_BALL_SHINING, 0},
|
|
DIG_SPRITE_DUMMY
|
|
};
|
|
|
|
static const struct DigitalDisplaySprite *const sDigitalDisplayScenes[] = {
|
|
[DIG_DISPLAY_INSERT_BET] = sDigitalDisplay_InsertBet,
|
|
[DIG_DISPLAY_STOP_REEL] = sDigitalDisplay_StopReel,
|
|
[DIG_DISPLAY_WIN] = sDigitalDisplay_Win,
|
|
[DIG_DISPLAY_LOSE] = sDigitalDisplay_Lose,
|
|
[DIG_DISPLAY_REEL_TIME] = sDigitalDisplay_ReelTime,
|
|
[DIG_DISPLAY_BONUS_REG] = sDigitalDisplay_BonusRegular,
|
|
[DIG_DISPLAY_BONUS_BIG] = sDigitalDisplay_BonusBig
|
|
};
|
|
|
|
static void (*const sDigitalDisplaySceneExitCallbacks[])(void) = {
|
|
[DIG_DISPLAY_INSERT_BET] = EndDigitalDisplayScene_InsertBet,
|
|
[DIG_DISPLAY_STOP_REEL] = EndDigitalDisplayScene_StopReel,
|
|
[DIG_DISPLAY_WIN] = EndDigitalDisplayScene_Win,
|
|
[DIG_DISPLAY_LOSE] = EndDigitalDisplayScene_Dummy,
|
|
[DIG_DISPLAY_REEL_TIME] = EndDigitalDisplayScene_Dummy,
|
|
[DIG_DISPLAY_BONUS_REG] = EndDigitalDisplayScene_Win,
|
|
[DIG_DISPLAY_BONUS_BIG] = EndDigitalDisplayScene_Win
|
|
};
|
|
|
|
static const struct OamData sOam_8x8 =
|
|
{
|
|
.y = 0,
|
|
.affineMode = ST_OAM_AFFINE_OFF,
|
|
.objMode = ST_OAM_OBJ_NORMAL,
|
|
.mosaic = FALSE,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.x = 0,
|
|
.matrixNum = 0,
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileNum = 0,
|
|
.priority = 0,
|
|
.paletteNum = 0,
|
|
.affineParam = 0,
|
|
};
|
|
|
|
static const struct OamData sOam_8x16 =
|
|
{
|
|
.y = 0,
|
|
.affineMode = ST_OAM_AFFINE_OFF,
|
|
.objMode = ST_OAM_OBJ_NORMAL,
|
|
.mosaic = FALSE,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(8x16),
|
|
.x = 0,
|
|
.matrixNum = 0,
|
|
.size = SPRITE_SIZE(8x16),
|
|
.tileNum = 0,
|
|
.priority = 0,
|
|
.paletteNum = 0,
|
|
.affineParam = 0,
|
|
};
|
|
|
|
static const struct OamData sOam_16x16 =
|
|
{
|
|
.y = 0,
|
|
.affineMode = ST_OAM_AFFINE_OFF,
|
|
.objMode = ST_OAM_OBJ_NORMAL,
|
|
.mosaic = FALSE,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(16x16),
|
|
.x = 0,
|
|
.matrixNum = 0,
|
|
.size = SPRITE_SIZE(16x16),
|
|
.tileNum = 0,
|
|
.priority = 0,
|
|
.paletteNum = 0,
|
|
.affineParam = 0,
|
|
};
|
|
|
|
static const struct OamData sOam_16x32 =
|
|
{
|
|
.y = 0,
|
|
.affineMode = ST_OAM_AFFINE_OFF,
|
|
.objMode = ST_OAM_OBJ_NORMAL,
|
|
.mosaic = FALSE,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(16x32),
|
|
.x = 0,
|
|
.matrixNum = 0,
|
|
.size = SPRITE_SIZE(16x32),
|
|
.tileNum = 0,
|
|
.priority = 0,
|
|
.paletteNum = 0,
|
|
.affineParam = 0,
|
|
};
|
|
|
|
static const struct OamData sOam_32x32 =
|
|
{
|
|
.y = 0,
|
|
.affineMode = ST_OAM_AFFINE_OFF,
|
|
.objMode = ST_OAM_OBJ_NORMAL,
|
|
.mosaic = FALSE,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(32x32),
|
|
.x = 0,
|
|
.matrixNum = 0,
|
|
.size = SPRITE_SIZE(32x32),
|
|
.tileNum = 0,
|
|
.priority = 0,
|
|
.paletteNum = 0,
|
|
.affineParam = 0,
|
|
};
|
|
|
|
static const struct OamData sOam_32x64 =
|
|
{
|
|
.y = 0,
|
|
.affineMode = ST_OAM_AFFINE_OFF,
|
|
.objMode = ST_OAM_OBJ_NORMAL,
|
|
.mosaic = FALSE,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(32x64),
|
|
.x = 0,
|
|
.matrixNum = 0,
|
|
.size = SPRITE_SIZE(32x64),
|
|
.tileNum = 0,
|
|
.priority = 0,
|
|
.paletteNum = 0,
|
|
.affineParam = 0,
|
|
};
|
|
|
|
static const struct OamData sOam_64x32 =
|
|
{
|
|
.y = 0,
|
|
.affineMode = ST_OAM_AFFINE_OFF,
|
|
.objMode = ST_OAM_OBJ_NORMAL,
|
|
.mosaic = FALSE,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(64x32),
|
|
.x = 0,
|
|
.matrixNum = 0,
|
|
.size = SPRITE_SIZE(64x32),
|
|
.tileNum = 0,
|
|
.priority = 0,
|
|
.paletteNum = 0,
|
|
.affineParam = 0,
|
|
};
|
|
|
|
static const struct OamData sOam_64x64 =
|
|
{
|
|
.y = 0,
|
|
.affineMode = ST_OAM_AFFINE_OFF,
|
|
.objMode = ST_OAM_OBJ_NORMAL,
|
|
.mosaic = FALSE,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(64x64),
|
|
.x = 0,
|
|
.matrixNum = 0,
|
|
.size = SPRITE_SIZE(64x64),
|
|
.tileNum = 0,
|
|
.priority = 0,
|
|
.paletteNum = 0,
|
|
.affineParam = 0,
|
|
};
|
|
|
|
static const struct SpriteFrameImage sImageTable_ReelTimeNumbers[] =
|
|
{
|
|
{ gSlotMachineReelTimeNumber0, 0x80 },
|
|
{ gSlotMachineReelTimeNumber1, 0x80 },
|
|
{ gSlotMachineReelTimeNumber2, 0x80 },
|
|
{ gSlotMachineReelTimeNumber3, 0x80 },
|
|
{ gSlotMachineReelTimeNumber4, 0x80 },
|
|
{ gSlotMachineReelTimeNumber5, 0x80 },
|
|
};
|
|
|
|
static const struct SpriteFrameImage sImageTable_ReelTimeShadow[] = { gSlotMachineReelTimeShadow, 0x200 };
|
|
static const struct SpriteFrameImage sImageTable_ReelTimeNumberGap[] = { gSlotMachineReelTimeNumberGap_Gfx, 0x40 };
|
|
|
|
static const struct SpriteFrameImage sImageTable_ReelTimeBolt[] =
|
|
{
|
|
{ gSlotMachineReelTimeBolt0, 0x100 },
|
|
{ gSlotMachineReelTimeBolt1, 0x100 },
|
|
};
|
|
|
|
static const struct SpriteFrameImage sImageTable_ReelTimePikachuAura[] = { gSlotMachineReelTimePikaAura, 0x400 };
|
|
|
|
static const struct SpriteFrameImage sImageTable_ReelTimeExplosion[] =
|
|
{
|
|
{ gSlotMachineReelTimeExplosion0, 0x200 },
|
|
{ gSlotMachineReelTimeExplosion1, 0x200 },
|
|
};
|
|
|
|
static const struct SpriteFrameImage sImageTable_ReelTimeDuck[] = { gSlotMachineReelTimeDuck, 0x20};
|
|
static const struct SpriteFrameImage sImageTable_ReelTimeSmoke[] = { gSlotMachineReelTimeSmoke, 0x80};
|
|
static const struct SpriteFrameImage sImageTable_PikaPowerBolt[] = { gSlotMachinePikaPowerBolt, 0x20};
|
|
|
|
static const union AnimCmd sAnim_SingleFrame[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_ReelTimeDuck[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 1),
|
|
ANIMCMD_JUMP(0)
|
|
};
|
|
|
|
static const union AnimCmd sAnim_ReelTimePikachu_Still[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 16),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_ReelTimePikachu_ChargingSlow[] =
|
|
{
|
|
ANIMCMD_FRAME(1, 16),
|
|
ANIMCMD_FRAME(0, 16),
|
|
ANIMCMD_JUMP(0)
|
|
};
|
|
|
|
static const union AnimCmd sAnim_ReelTimePikachu_ChargingMedium[] =
|
|
{
|
|
ANIMCMD_FRAME(1, 8),
|
|
ANIMCMD_FRAME(0, 8),
|
|
ANIMCMD_JUMP(0)
|
|
};
|
|
|
|
static const union AnimCmd sAnim_ReelTimePikachu_ChargingFast[] =
|
|
{
|
|
ANIMCMD_FRAME(1, 4),
|
|
ANIMCMD_FRAME(0, 4),
|
|
ANIMCMD_JUMP(0)
|
|
};
|
|
|
|
static const union AnimCmd sAnim_ReelTimePikachu_Cheering[] =
|
|
{
|
|
ANIMCMD_FRAME(2, 32),
|
|
ANIMCMD_FRAME(3, 32),
|
|
ANIMCMD_JUMP(0)
|
|
};
|
|
|
|
static const union AnimCmd sAnim_ReelTimePikachu_FellOver[] =
|
|
{
|
|
ANIMCMD_FRAME(4, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_ReelTimeNumber_0[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_ReelTimeNumber_1[] =
|
|
{
|
|
ANIMCMD_FRAME(1, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_ReelTimeNumber_2[] =
|
|
{
|
|
ANIMCMD_FRAME(2, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_ReelTimeNumber_3[] =
|
|
{
|
|
ANIMCMD_FRAME(3, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_ReelTimeNumber_4[] =
|
|
{
|
|
ANIMCMD_FRAME(4, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_ReelTimeNumber_5[] =
|
|
{
|
|
ANIMCMD_FRAME(5, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
|
|
static const union AnimCmd sAnim_ReelTimeBolt[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 4),
|
|
ANIMCMD_FRAME(1, 4),
|
|
ANIMCMD_JUMP(0)
|
|
};
|
|
|
|
static const union AnimCmd sAnim_ReelTimeExplosion[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 16),
|
|
ANIMCMD_FRAME(1, 16),
|
|
ANIMCMD_JUMP(0)
|
|
};
|
|
|
|
static const union AnimCmd sAnim_DigitalDisplay_AButton_Flashing[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 30),
|
|
ANIMCMD_FRAME(1, 30),
|
|
ANIMCMD_JUMP(0)
|
|
};
|
|
|
|
static const union AnimCmd sAnim_DigitalDisplay_AButton_Static[] =
|
|
{
|
|
ANIMCMD_FRAME(1, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_DigitalDisplay_DPad_Flashing[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 30),
|
|
ANIMCMD_FRAME(1, 30),
|
|
ANIMCMD_JUMP(0)
|
|
};
|
|
|
|
static const union AnimCmd sAnim_DigitalDisplay_Pokeball_Rocking[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 16),
|
|
ANIMCMD_FRAME(1, 16),
|
|
ANIMCMD_FRAME(0, 16),
|
|
ANIMCMD_FRAME(1, 16, .hFlip = TRUE),
|
|
ANIMCMD_JUMP(0)
|
|
};
|
|
|
|
static const union AnimCmd sAnim_DigitalDisplay_Pokeball_Static[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_DigitalDisplay_Number_1[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_DigitalDisplay_Number_2[] =
|
|
{
|
|
ANIMCMD_FRAME(1, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_DigitalDisplay_Number_3[] =
|
|
{
|
|
ANIMCMD_FRAME(2, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_DigitalDisplay_Number_4[] =
|
|
{
|
|
ANIMCMD_FRAME(3, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_DigitalDisplay_Number_5[] =
|
|
{
|
|
ANIMCMD_FRAME(4, 1),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd *const sAnims_SingleFrame[] =
|
|
{
|
|
sAnim_SingleFrame
|
|
};
|
|
|
|
static const union AnimCmd *const sAnims_ReelTimeDuck[] =
|
|
{
|
|
sAnim_ReelTimeDuck
|
|
};
|
|
|
|
static const union AnimCmd *const sAnims_ReelTimePikachu[] =
|
|
{
|
|
sAnim_ReelTimePikachu_Still,
|
|
sAnim_ReelTimePikachu_ChargingSlow,
|
|
sAnim_ReelTimePikachu_ChargingMedium,
|
|
sAnim_ReelTimePikachu_ChargingFast,
|
|
sAnim_ReelTimePikachu_Cheering,
|
|
sAnim_ReelTimePikachu_FellOver
|
|
};
|
|
|
|
static const union AnimCmd *const sAnims_ReelTimeNumbers[] =
|
|
{
|
|
sAnim_ReelTimeNumber_0,
|
|
sAnim_ReelTimeNumber_1,
|
|
sAnim_ReelTimeNumber_2,
|
|
sAnim_ReelTimeNumber_3,
|
|
sAnim_ReelTimeNumber_4,
|
|
sAnim_ReelTimeNumber_5
|
|
};
|
|
|
|
static const union AnimCmd *const sAnims_ReelTimeBolt[] =
|
|
{
|
|
sAnim_ReelTimeBolt
|
|
};
|
|
|
|
static const union AnimCmd *const sAnims_ReelTimeExplosion[] =
|
|
{
|
|
sAnim_ReelTimeExplosion
|
|
};
|
|
|
|
static const union AnimCmd *const sAnims_DigitalDisplay_AButton[] =
|
|
{
|
|
sAnim_DigitalDisplay_AButton_Flashing,
|
|
sAnim_DigitalDisplay_AButton_Static
|
|
};
|
|
|
|
static const union AnimCmd *const sAnims_DigitalDisplay_DPad[] =
|
|
{
|
|
sAnim_DigitalDisplay_DPad_Flashing
|
|
};
|
|
|
|
static const union AnimCmd *const sAnims_DigitalDisplay_Pokeball[] =
|
|
{
|
|
sAnim_DigitalDisplay_Pokeball_Rocking,
|
|
sAnim_DigitalDisplay_Pokeball_Static
|
|
};
|
|
|
|
static const union AnimCmd *const sAnims_DigitalDisplay_Number[] =
|
|
{
|
|
sAnim_DigitalDisplay_Number_1,
|
|
sAnim_DigitalDisplay_Number_2,
|
|
sAnim_DigitalDisplay_Number_3,
|
|
sAnim_DigitalDisplay_Number_4,
|
|
sAnim_DigitalDisplay_Number_5
|
|
};
|
|
|
|
|
|
static const union AffineAnimCmd sAffineAnim_ReelTimeSmoke[] =
|
|
{
|
|
AFFINEANIMCMD_FRAME(16, 16, 0, 0),
|
|
AFFINEANIMCMD_LOOP(0),
|
|
AFFINEANIMCMD_FRAME(1, 1, 0, 1),
|
|
AFFINEANIMCMD_LOOP(0xFF),
|
|
AFFINEANIMCMD_END
|
|
};
|
|
|
|
static const union AffineAnimCmd *const sAffineAnims_ReelTimeSmoke[] =
|
|
{
|
|
sAffineAnim_ReelTimeSmoke
|
|
};
|
|
|
|
// Spin as it appears
|
|
static const union AffineAnimCmd sAffineAnim_PikaPowerBolt[] =
|
|
{
|
|
AFFINEANIMCMD_FRAME(0, 0, 8, 32),
|
|
AFFINEANIMCMD_FRAME(0, 0, 6, 32),
|
|
AFFINEANIMCMD_FRAME(0, 0, 4, 16),
|
|
AFFINEANIMCMD_FRAME(0, 0, 12, 2),
|
|
AFFINEANIMCMD_FRAME(0, 0, -12, 4),
|
|
AFFINEANIMCMD_FRAME(0, 0, 12, 2),
|
|
AFFINEANIMCMD_FRAME(0, 0, 12, 2),
|
|
AFFINEANIMCMD_FRAME(0, 0, -12, 4),
|
|
AFFINEANIMCMD_FRAME(0, 0, 12, 2),
|
|
AFFINEANIMCMD_END
|
|
};
|
|
|
|
static const union AffineAnimCmd *const sAffineAnims_PikaPowerBolt[] =
|
|
{
|
|
sAffineAnim_PikaPowerBolt
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelSymbol =
|
|
{
|
|
.tileTag = GFXTAG_SYMBOLS_START,
|
|
.paletteTag = PALTAG_REEL,
|
|
.oam = &sOam_32x32,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCB_ReelSymbol
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_CoinNumber =
|
|
{
|
|
.tileTag = GFXTAG_NUMBERS_START,
|
|
.paletteTag = PALTAG_MISC,
|
|
.oam = &sOam_8x16,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCB_CoinNumber
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelBackground =
|
|
{
|
|
.tileTag = GFXTAG_REEL_BG,
|
|
.paletteTag = PALTAG_REEL,
|
|
.oam = &sOam_64x64,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimePikachu =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_REEL_TIME_PIKACHU,
|
|
.oam = &sOam_64x64,
|
|
.anims = sAnims_ReelTimePikachu,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCB_ReelTimePikachu
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeMachineAntennae =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_REEL_TIME_MISC,
|
|
.oam = &sOam_8x16,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeMachine =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_REEL_TIME_MACHINE,
|
|
.oam = &sOam_8x16,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_BrokenReelTimeMachine =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_REEL_TIME_MACHINE,
|
|
.oam = &sOam_8x16,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeNumbers =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_MISC,
|
|
.oam = &sOam_16x16,
|
|
.anims = sAnims_ReelTimeNumbers,
|
|
.images = sImageTable_ReelTimeNumbers,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCB_ReelTimeNumbers
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeShadow =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_MISC,
|
|
.oam = &sOam_16x16,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = sImageTable_ReelTimeShadow,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeNumberGap =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_MISC,
|
|
.oam = &sOam_16x16,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = sImageTable_ReelTimeNumberGap,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeBolt =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_MISC,
|
|
.oam = &sOam_16x32,
|
|
.anims = sAnims_ReelTimeBolt,
|
|
.images = sImageTable_ReelTimeBolt,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCB_ReelTimeBolt
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimePikachuAura =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_PIKA_AURA,
|
|
.oam = &sOam_32x64,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = sImageTable_ReelTimePikachuAura,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCB_ReelTimePikachuAura
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeExplosion =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_EXPLOSION,
|
|
.oam = &sOam_32x32,
|
|
.anims = sAnims_ReelTimeExplosion,
|
|
.images = sImageTable_ReelTimeExplosion,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCB_ReelTimeExplosion
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeDuck =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_MISC,
|
|
.oam = &sOam_8x8,
|
|
.anims = sAnims_ReelTimeDuck,
|
|
.images = sImageTable_ReelTimeDuck,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCB_ReelTimeDuck
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_ReelTimeSmoke =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_MISC,
|
|
.oam = &sOam_16x16,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = sImageTable_ReelTimeSmoke,
|
|
.affineAnims = sAffineAnims_ReelTimeSmoke,
|
|
.callback = SpriteCB_ReelTimeSmoke
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_DigitalDisplay_Reel =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_DIG_DISPLAY,
|
|
.oam = &sOam_8x8,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_DigitalDisplay_Time =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_DIG_DISPLAY,
|
|
.oam = &sOam_8x8,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_DigitalDisplay_Insert =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_DIG_DISPLAY,
|
|
.oam = &sOam_8x8,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_DigitalDisplay_Stop =
|
|
{
|
|
.tileTag = GFXTAG_STOP,
|
|
.paletteTag = PALTAG_DIG_DISPLAY,
|
|
.oam = &sOam_8x8,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_DigitalDisplay_Win =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_DIG_DISPLAY,
|
|
.oam = &sOam_64x32,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_DigitalDisplay_Lose =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_DIG_DISPLAY,
|
|
.oam = &sOam_64x32,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_DigitalDisplay_Bonus =
|
|
{
|
|
.tileTag = GFXTAG_BONUS,
|
|
.paletteTag = PALTAG_DIG_DISPLAY,
|
|
.oam = &sOam_8x8,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_DigitalDisplay_Big =
|
|
{
|
|
.tileTag = GFXTAG_BIG,
|
|
.paletteTag = PALTAG_DIG_DISPLAY,
|
|
.oam = &sOam_8x8,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_DigitalDisplay_Reg =
|
|
{
|
|
.tileTag = GFXTAG_REG,
|
|
.paletteTag = PALTAG_DIG_DISPLAY,
|
|
.oam = &sOam_8x8,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_DigitalDisplay_AButton =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_DIG_DISPLAY,
|
|
.oam = &sOam_32x32,
|
|
.anims = sAnims_DigitalDisplay_AButton,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_DigitalDisplay_Smoke =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_DIG_DISPLAY,
|
|
.oam = &sOam_8x8,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_DigitalDisplay_Number =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_DIG_DISPLAY,
|
|
.oam = &sOam_16x16,
|
|
.anims = sAnims_DigitalDisplay_Number,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_DigitalDisplay_Pokeball =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_DIG_DISPLAY,
|
|
.oam = &sOam_8x8,
|
|
.anims = sAnims_DigitalDisplay_Pokeball,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_DigitalDisplay_DPad =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_DIG_DISPLAY,
|
|
.oam = &sOam_8x8,
|
|
.anims = sAnims_DigitalDisplay_DPad,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_PikaPowerBolt =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = PALTAG_MISC,
|
|
.oam = &sOam_8x8,
|
|
.anims = sAnims_SingleFrame,
|
|
.images = sImageTable_PikaPowerBolt,
|
|
.affineAnims = sAffineAnims_PikaPowerBolt,
|
|
.callback = SpriteCB_PikaPowerBolt
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_ReelBackground[] =
|
|
{
|
|
{
|
|
.x = -64,
|
|
.y = -64,
|
|
.shape = SPRITE_SHAPE(64x64),
|
|
.size = SPRITE_SIZE(64x64),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = -64,
|
|
.shape = SPRITE_SHAPE(64x64),
|
|
.size = SPRITE_SIZE(64x64),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -64,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(64x64),
|
|
.size = SPRITE_SIZE(64x64),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(64x64),
|
|
.size = SPRITE_SIZE(64x64),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_ReelBackground[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_ReelBackground), sSubsprites_ReelBackground
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_ReelTimeMachineAntennae[] =
|
|
{
|
|
{
|
|
.x = -32,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 0,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 4,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = -32,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 8,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 12,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = -32,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 16,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 20,
|
|
.priority = 1
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_ReelTimeMachineAntennae[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_ReelTimeMachineAntennae), sSubsprites_ReelTimeMachineAntennae
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_ReelTimeMachine[] =
|
|
{
|
|
{
|
|
.x = -32,
|
|
.y = -20,
|
|
.shape = SPRITE_SHAPE(64x32),
|
|
.size = SPRITE_SIZE(64x32),
|
|
.tileOffset = 0,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = -32,
|
|
.y = 12,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 32,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = 12,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 36,
|
|
.priority = 1,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_ReelTimeMachine[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_ReelTimeMachine), sSubsprites_ReelTimeMachine
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_BrokenReelTimeMachine[] =
|
|
{
|
|
{
|
|
.x = -32,
|
|
.y = -24,
|
|
.shape = SPRITE_SHAPE(64x32),
|
|
.size = SPRITE_SIZE(64x32),
|
|
.tileOffset = 0,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = -32,
|
|
.y = 8,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 32,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = 8,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 36,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = -32,
|
|
.y = 16,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 40,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = 16,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 44,
|
|
.priority = 1,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_BrokenReelTimeMachine[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_BrokenReelTimeMachine), sSubsprites_BrokenReelTimeMachine
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_ReelTimeShadow[] =
|
|
{
|
|
{
|
|
.x = -32,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 0,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 4,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = -32,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 8,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 12,
|
|
.priority = 1,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_ReelTimeShadow[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_ReelTimeShadow), sSubsprites_ReelTimeShadow
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_ReelTimeNumberGap[] =
|
|
{
|
|
{
|
|
.x = -8,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 0,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = -8,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 0,
|
|
.priority = 1,
|
|
},
|
|
{
|
|
.x = -8,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 0,
|
|
.priority = 1,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_ReelTimeNumberGap[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_ReelTimeNumberGap), sSubsprites_ReelTimeNumberGap
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_Reel[] =
|
|
{
|
|
{
|
|
.x = -32,
|
|
.y = -24,
|
|
.shape = SPRITE_SHAPE(64x32),
|
|
.size = SPRITE_SIZE(64x32),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -32,
|
|
.y = 8,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 32,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = 8,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 36,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -32,
|
|
.y = 16,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 40,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = 16,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 44,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_Reel[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_Reel), sSubsprites_DigitalDisplay_Reel
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_Time[] =
|
|
{
|
|
{
|
|
.x = -32,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 4,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -32,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 8,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 12,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_Time[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_Time), sSubsprites_DigitalDisplay_Time
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_Insert[] =
|
|
{
|
|
{
|
|
.x = -32,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 4,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -32,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 8,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 12,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_Insert[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_Insert), sSubsprites_DigitalDisplay_Insert
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_Unused1[] =
|
|
{
|
|
{
|
|
.x = -32,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 4,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -32,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 8,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 12,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_Unused1[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_Unused1), sSubsprites_DigitalDisplay_Unused1
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_Win[] =
|
|
{
|
|
{
|
|
.x = -32,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 4,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -32,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 8,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 12,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -32,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 16,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 20,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_Win[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_Win), sSubsprites_DigitalDisplay_Win
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_Smoke[] =
|
|
{
|
|
{
|
|
.x = -16,
|
|
.y = -16,
|
|
.shape = SPRITE_SHAPE(32x32),
|
|
.size = SPRITE_SIZE(32x32),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_Unused2[] =
|
|
{
|
|
{
|
|
.x = -8,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(16x16),
|
|
.size = SPRITE_SIZE(16x16),
|
|
.tileOffset = 16,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_Smoke[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_Smoke), sSubsprites_DigitalDisplay_Smoke
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_Unused2[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_Unused2), sSubsprites_DigitalDisplay_Unused2
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_Pokeball[] =
|
|
{
|
|
{
|
|
.x = -24,
|
|
.y = -24,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 8,
|
|
-24,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 4,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -24,
|
|
.y = -16,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 6,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 8,
|
|
.y = -16,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 10,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -24,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 12,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 8,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 16,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -24,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 18,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 8,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 22,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -24,
|
|
.y = 8,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 24,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 8,
|
|
.y = 8,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 28,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -24,
|
|
.y = 16,
|
|
.shape = SPRITE_SHAPE(32x8),
|
|
.size = SPRITE_SIZE(32x8),
|
|
.tileOffset = 30,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 8,
|
|
.y = 16,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 34,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_Pokeball[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_Pokeball), sSubsprites_DigitalDisplay_Pokeball
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_DPad[] =
|
|
{
|
|
{
|
|
.x = -16,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(32x16),
|
|
.size = SPRITE_SIZE(32x16),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -16,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 8,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 0,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 10,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_DPad[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_DPad), sSubsprites_DigitalDisplay_DPad
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_StopS[] =
|
|
{
|
|
{
|
|
.x = -8,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -8,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 8,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_StopS[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_StopS), sSubsprites_DigitalDisplay_StopS
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_StopT[] =
|
|
{
|
|
{
|
|
.x = -8,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 2,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -8,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 10,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_StopT[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_StopT), sSubsprites_DigitalDisplay_StopT
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_StopO[] =
|
|
{
|
|
{
|
|
.x = -8,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 4,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -8,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 12,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_StopO[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_StopO), sSubsprites_DigitalDisplay_StopO
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_StopP[] =
|
|
{
|
|
{
|
|
.x = -8,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 6,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -8,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 14,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_StopP[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_StopP), sSubsprites_DigitalDisplay_StopP
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_BonusB[] =
|
|
{
|
|
{
|
|
.x = -8,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -8,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 8,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_BonusB[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_BonusB), sSubsprites_DigitalDisplay_BonusB
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_BonusO[] =
|
|
{
|
|
{
|
|
.x = -4,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 2,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -4,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 10,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_BonusO[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_BonusO), sSubsprites_DigitalDisplay_BonusO
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_BonusN[] =
|
|
{
|
|
{
|
|
.x = -8,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 3,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -8,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 11,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_BonusN[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_BonusN), sSubsprites_DigitalDisplay_BonusN
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_BonusU[] =
|
|
{
|
|
{
|
|
.x = -4,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 5,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -4,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 13,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_BonusU[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_BonusU), sSubsprites_DigitalDisplay_BonusU
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_BonusS[] =
|
|
{
|
|
{
|
|
.x = -8,
|
|
.y = -8,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 6,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -8,
|
|
.y = 0,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 14,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_BonusS[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_BonusS), sSubsprites_DigitalDisplay_BonusS
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_BigB[] =
|
|
{
|
|
{
|
|
.x = -12,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 4,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 2,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -12,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 8,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 4,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 10,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -12,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 16,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 4,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 18,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_BigB[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_BigB), sSubsprites_DigitalDisplay_BigB
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_BigI[] =
|
|
{
|
|
{
|
|
.x = -8,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 3,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -8,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 11,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -8,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 19,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_BigI[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_BigI), sSubsprites_DigitalDisplay_BigI
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_BigG[] =
|
|
{
|
|
{
|
|
.x = -12,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 5,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 4,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 7,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -12,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 13,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 4,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 15,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -12,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 21,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 4,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 23,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_BigG[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_BigG), sSubsprites_DigitalDisplay_BigG
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_RegR[] =
|
|
{
|
|
{
|
|
.x = -12,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 0,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 4,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 2,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -12,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 8,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 4,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 10,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -12,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 16,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 4,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 18,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_RegR[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_RegR), sSubsprites_DigitalDisplay_RegR
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_RegE[] =
|
|
{
|
|
{
|
|
.x = -8,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 3,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -8,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 11,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -8,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 19,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_RegE[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_RegE), sSubsprites_DigitalDisplay_RegE
|
|
};
|
|
|
|
static const struct Subsprite sSubsprites_DigitalDisplay_RegG[] =
|
|
{
|
|
{
|
|
.x = -12,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 5,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 4,
|
|
.y = -12,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 7,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -12,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 13,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 4,
|
|
.y = -4,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 15,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = -12,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(16x8),
|
|
.size = SPRITE_SIZE(16x8),
|
|
.tileOffset = 21,
|
|
.priority = 3,
|
|
},
|
|
{
|
|
.x = 4,
|
|
.y = 4,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileOffset = 23,
|
|
.priority = 3,
|
|
}
|
|
};
|
|
|
|
static const struct SubspriteTable sSubspriteTable_DigitalDisplay_RegG[] =
|
|
{
|
|
ARRAY_COUNT(sSubsprites_DigitalDisplay_RegG), sSubsprites_DigitalDisplay_RegG
|
|
};
|
|
|
|
static const struct SpriteTemplate *const sSpriteTemplates_DigitalDisplay[NUM_DIG_DISPLAY_SPRITES] =
|
|
{
|
|
[DIG_SPRITE_REEL] = &sSpriteTemplate_DigitalDisplay_Reel,
|
|
[DIG_SPRITE_TIME] = &sSpriteTemplate_DigitalDisplay_Time,
|
|
[DIG_SPRITE_INSERT] = &sSpriteTemplate_DigitalDisplay_Insert,
|
|
[DIG_SPRITE_WIN] = &sSpriteTemplate_DigitalDisplay_Win,
|
|
[DIG_SPRITE_LOSE] = &sSpriteTemplate_DigitalDisplay_Lose,
|
|
[DIG_SPRITE_A_BUTTON] = &sSpriteTemplate_DigitalDisplay_AButton,
|
|
[DIG_SPRITE_SMOKE] = &sSpriteTemplate_DigitalDisplay_Smoke,
|
|
[DIG_SPRITE_NUMBER] = &sSpriteTemplate_DigitalDisplay_Number,
|
|
[DIG_SPRITE_POKE_BALL] = &sSpriteTemplate_DigitalDisplay_Pokeball,
|
|
[DIG_SPRITE_D_PAD] = &sSpriteTemplate_DigitalDisplay_DPad,
|
|
[DIG_SPRITE_STOP_S] = &sSpriteTemplate_DigitalDisplay_Stop,
|
|
[DIG_SPRITE_STOP_T] = &sSpriteTemplate_DigitalDisplay_Stop,
|
|
[DIG_SPRITE_STOP_O] = &sSpriteTemplate_DigitalDisplay_Stop,
|
|
[DIG_SPRITE_STOP_P] = &sSpriteTemplate_DigitalDisplay_Stop,
|
|
[DIG_SPRITE_BONUS_B] = &sSpriteTemplate_DigitalDisplay_Bonus,
|
|
[DIG_SPRITE_BONUS_O] = &sSpriteTemplate_DigitalDisplay_Bonus,
|
|
[DIG_SPRITE_BONUS_N] = &sSpriteTemplate_DigitalDisplay_Bonus,
|
|
[DIG_SPRITE_BONUS_U] = &sSpriteTemplate_DigitalDisplay_Bonus,
|
|
[DIG_SPRITE_BONUS_S] = &sSpriteTemplate_DigitalDisplay_Bonus,
|
|
[DIG_SPRITE_BIG_B] = &sSpriteTemplate_DigitalDisplay_Big,
|
|
[DIG_SPRITE_BIG_I] = &sSpriteTemplate_DigitalDisplay_Big,
|
|
[DIG_SPRITE_BIG_G] = &sSpriteTemplate_DigitalDisplay_Big,
|
|
[DIG_SPRITE_REG_R] = &sSpriteTemplate_DigitalDisplay_Reg,
|
|
[DIG_SPRITE_REG_E] = &sSpriteTemplate_DigitalDisplay_Reg,
|
|
[DIG_SPRITE_REG_G] = &sSpriteTemplate_DigitalDisplay_Reg,
|
|
[DIG_SPRITE_EMPTY] = &gDummySpriteTemplate
|
|
};
|
|
|
|
static const struct SubspriteTable *const sSubspriteTables_DigitalDisplay[NUM_DIG_DISPLAY_SPRITES] =
|
|
{
|
|
[DIG_SPRITE_REEL] = sSubspriteTable_DigitalDisplay_Reel,
|
|
[DIG_SPRITE_TIME] = sSubspriteTable_DigitalDisplay_Time,
|
|
[DIG_SPRITE_INSERT] = sSubspriteTable_DigitalDisplay_Insert,
|
|
[DIG_SPRITE_WIN] = sSubspriteTable_DigitalDisplay_Win,
|
|
[DIG_SPRITE_LOSE] = NULL,
|
|
[DIG_SPRITE_A_BUTTON] = NULL,
|
|
[DIG_SPRITE_SMOKE] = sSubspriteTable_DigitalDisplay_Smoke,
|
|
[DIG_SPRITE_NUMBER] = NULL,
|
|
[DIG_SPRITE_POKE_BALL] = sSubspriteTable_DigitalDisplay_Pokeball,
|
|
[DIG_SPRITE_D_PAD] = sSubspriteTable_DigitalDisplay_DPad,
|
|
[DIG_SPRITE_STOP_S] = sSubspriteTable_DigitalDisplay_StopS,
|
|
[DIG_SPRITE_STOP_T] = sSubspriteTable_DigitalDisplay_StopT,
|
|
[DIG_SPRITE_STOP_O] = sSubspriteTable_DigitalDisplay_StopO,
|
|
[DIG_SPRITE_STOP_P] = sSubspriteTable_DigitalDisplay_StopP,
|
|
[DIG_SPRITE_BONUS_B] = sSubspriteTable_DigitalDisplay_BonusB,
|
|
[DIG_SPRITE_BONUS_O] = sSubspriteTable_DigitalDisplay_BonusO,
|
|
[DIG_SPRITE_BONUS_N] = sSubspriteTable_DigitalDisplay_BonusN,
|
|
[DIG_SPRITE_BONUS_U] = sSubspriteTable_DigitalDisplay_BonusU,
|
|
[DIG_SPRITE_BONUS_S] = sSubspriteTable_DigitalDisplay_BonusS,
|
|
[DIG_SPRITE_BIG_B] = sSubspriteTable_DigitalDisplay_BigB,
|
|
[DIG_SPRITE_BIG_I] = sSubspriteTable_DigitalDisplay_BigI,
|
|
[DIG_SPRITE_BIG_G] = sSubspriteTable_DigitalDisplay_BigG,
|
|
[DIG_SPRITE_REG_R] = sSubspriteTable_DigitalDisplay_RegR,
|
|
[DIG_SPRITE_REG_E] = sSubspriteTable_DigitalDisplay_RegE,
|
|
[DIG_SPRITE_REG_G] = sSubspriteTable_DigitalDisplay_RegG,
|
|
[DIG_SPRITE_EMPTY] = NULL
|
|
};
|
|
|
|
static const struct SpriteSheet sSlotMachineSpriteSheets[22] =
|
|
{
|
|
{ .data = gSlotMachineReelSymbol1Tiles, .size = 0x200, .tag = GFXTAG_7_RED },
|
|
{ .data = gSlotMachineReelSymbol2Tiles, .size = 0x200, .tag = GFXTAG_7_BLUE },
|
|
{ .data = gSlotMachineReelSymbol3Tiles, .size = 0x200, .tag = GFXTAG_AZURILL },
|
|
{ .data = gSlotMachineReelSymbol4Tiles, .size = 0x200, .tag = GFXTAG_LOTAD },
|
|
{ .data = gSlotMachineReelSymbol5Tiles, .size = 0x200, .tag = GFXTAG_CHERRY },
|
|
{ .data = gSlotMachineReelSymbol6Tiles, .size = 0x200, .tag = GFXTAG_POWER },
|
|
{ .data = gSlotMachineReelSymbol7Tiles, .size = 0x200, .tag = GFXTAG_REPLAY },
|
|
{ .data = gSlotMachineNumber0Tiles, .size = 0x40, .tag = GFXTAG_NUM_0 },
|
|
{ .data = gSlotMachineNumber1Tiles, .size = 0x40, .tag = GFXTAG_NUM_1 },
|
|
{ .data = gSlotMachineNumber2Tiles, .size = 0x40, .tag = GFXTAG_NUM_2 },
|
|
{ .data = gSlotMachineNumber3Tiles, .size = 0x40, .tag = GFXTAG_NUM_3 },
|
|
{ .data = gSlotMachineNumber4Tiles, .size = 0x40, .tag = GFXTAG_NUM_4 },
|
|
{ .data = gSlotMachineNumber5Tiles, .size = 0x40, .tag = GFXTAG_NUM_5 },
|
|
{ .data = gSlotMachineNumber6Tiles, .size = 0x40, .tag = GFXTAG_NUM_6 },
|
|
{ .data = gSlotMachineNumber7Tiles, .size = 0x40, .tag = GFXTAG_NUM_7 },
|
|
{ .data = gSlotMachineNumber8Tiles, .size = 0x40, .tag = GFXTAG_NUM_8 },
|
|
{ .data = gSlotMachineNumber9Tiles, .size = 0x40, .tag = GFXTAG_NUM_9 },
|
|
// skips GFXTAG_REEL_BG, which has its own spritesheet
|
|
// the data for these sheets is determined at runtime
|
|
{ .data = NULL, .size = 0x200, .tag = GFXTAG_STOP },
|
|
{ .data = NULL, .size = 0x200, .tag = GFXTAG_BONUS },
|
|
{ .data = NULL, .size = 0x300, .tag = GFXTAG_BIG },
|
|
{ .data = NULL, .size = 0x300, .tag = GFXTAG_REG },
|
|
{},
|
|
};
|
|
|
|
static const u8 *const sReelBackground_Tilemap = gSlotMachineReelBackground_Tilemap;
|
|
|
|
static const u16 sUnusedColors[] =
|
|
{
|
|
RGB(27, 27, 27),
|
|
RGB(8, 11, 26),
|
|
RGB(11, 21, 13),
|
|
RGB(31, 31, 31),
|
|
RGB(16, 26, 21),
|
|
RGB(0, 22, 31),
|
|
RGB(26, 21, 0),
|
|
RGB(26, 21, 0),
|
|
RGB(29, 15, 0),
|
|
RGB(29, 15, 0),
|
|
};
|
|
|
|
// The Bet 2 and 3 match line palettes are duplicated unnecessarily
|
|
static const u16 sMiddleRowLit_Pal[] = {RGB(17, 28, 31)};
|
|
static const u16 sTopRowLit_Pal[] = {RGB(31, 29, 16)};
|
|
static const u16 sBottomRowt_Pal[] = {RGB(31, 29, 16)};
|
|
static const u16 sNWSEDiagLit_Pal[] = {RGB(31, 21, 18)};
|
|
static const u16 sNESWDiagLit_Pal[] = {RGB(31, 21, 18)};
|
|
static const u16 *const sLitMatchLinePalTable[NUM_MATCH_LINES] =
|
|
{
|
|
[MATCH_MIDDLE_ROW] = sMiddleRowLit_Pal,
|
|
[MATCH_TOP_ROW] = sTopRowLit_Pal,
|
|
[MATCH_BOTTOM_ROW] = sBottomRowt_Pal,
|
|
[MATCH_NWSE_DIAG] = sNWSEDiagLit_Pal,
|
|
[MATCH_NESW_DIAG] = sNESWDiagLit_Pal,
|
|
};
|
|
|
|
static const u16 *const sDarkMatchLinePalTable[NUM_MATCH_LINES] =
|
|
{
|
|
[MATCH_MIDDLE_ROW] = &gSlotMachineMenu_Pal[BG_PLTT_ID(4) + 10],
|
|
[MATCH_TOP_ROW] = &gSlotMachineMenu_Pal[BG_PLTT_ID(4) + 11],
|
|
[MATCH_BOTTOM_ROW] = &gSlotMachineMenu_Pal[BG_PLTT_ID(4) + 12],
|
|
[MATCH_NWSE_DIAG] = &gSlotMachineMenu_Pal[BG_PLTT_ID(4) + 13],
|
|
[MATCH_NESW_DIAG] = &gSlotMachineMenu_Pal[BG_PLTT_ID(4) + 14],
|
|
};
|
|
|
|
static const u8 sMatchLinePalOffsets[NUM_MATCH_LINES] = {
|
|
[MATCH_MIDDLE_ROW] = BG_PLTT_ID(4) + 10,
|
|
[MATCH_TOP_ROW] = BG_PLTT_ID(4) + 11,
|
|
[MATCH_BOTTOM_ROW] = BG_PLTT_ID(4) + 12,
|
|
[MATCH_NWSE_DIAG] = BG_PLTT_ID(4) + 14, // Diag colors flipped for some reason
|
|
[MATCH_NESW_DIAG] = BG_PLTT_ID(4) + 13 // Doesn't matter as both are identical
|
|
};
|
|
|
|
static const u8 sBetToMatchLineIds[MAX_BET][2] =
|
|
{
|
|
{MATCH_MIDDLE_ROW, MATCH_MIDDLE_ROW}, // Bet 1
|
|
{MATCH_TOP_ROW, MATCH_BOTTOM_ROW}, // Bet 2
|
|
{MATCH_NWSE_DIAG, MATCH_NESW_DIAG}, // Bet 3
|
|
};
|
|
|
|
static const u8 sMatchLinesPerBet[MAX_BET] = { 1, 2, 2 };
|
|
|
|
// Flashing lights at top of slot machine, brightest point inside light goes from toward center of machine, to middle, to toward edges
|
|
static const u16 sFlashingLightsInside_Pal[] = INCBIN_U16("graphics/slot_machine/flashing_lights_inside.gbapal");
|
|
static const u16 sFlashingLightsMiddle_Pal[] = INCBIN_U16("graphics/slot_machine/flashing_lights_middle.gbapal");
|
|
static const u16 sFlashingLightsOutside_Pal[] = INCBIN_U16("graphics/slot_machine/flashing_lights_outside.gbapal");
|
|
static const u16 *const sFlashingLightsPalTable[] =
|
|
{
|
|
sFlashingLightsInside_Pal,
|
|
sFlashingLightsMiddle_Pal,
|
|
sFlashingLightsOutside_Pal,
|
|
};
|
|
|
|
static const u16 *const sSlotMachineMenu_Pal = {gSlotMachineMenu_Pal + 16};
|
|
|
|
static const u16 sPokeballShining0_Pal[] = INCBIN_U16("graphics/slot_machine/pokeball_shining_0.gbapal");
|
|
static const u16 sPokeballShining1_Pal[] = INCBIN_U16("graphics/slot_machine/pokeball_shining_1.gbapal");
|
|
static const u16 sPokeballShining2_Pal[] = INCBIN_U16("graphics/slot_machine/pokeball_shining_2.gbapal");
|
|
static const u16 *const sPokeballShiningPalTable[] =
|
|
{
|
|
sPokeballShining0_Pal, // Streak on left side of ball
|
|
sPokeballShining1_Pal, // Streak in middle of ball
|
|
sPokeballShining2_Pal, // Streak on right side of ball
|
|
gSlotMachineDigitalDisplay_Pal, // Back to normal
|
|
};
|
|
|
|
static const u16 *const sDigitalDisplay_Pal = gSlotMachineDigitalDisplay_Pal;
|
|
static const u16 sUnkPalette[16] = {
|
|
[1] = RGB_WHITEALPHA,
|
|
[3] = RGB(8, 8, 8),
|
|
};
|
|
|
|
static const struct SpritePalette sSlotMachineSpritePalettes[] =
|
|
{
|
|
{ .data = gSlotMachineReelSymbols_Pal, .tag = PALTAG_REEL},
|
|
{ .data = gSlotMachineReelTimePikachu_Pal, .tag = PALTAG_REEL_TIME_PIKACHU},
|
|
{ .data = gSlotMachineReelTimeMisc_Pal, .tag = PALTAG_REEL_TIME_MISC},
|
|
{ .data = gSlotMachineReelTimeMachine_Pal, .tag = PALTAG_REEL_TIME_MACHINE},
|
|
{ .data = gSlotMachineMisc_Pal, .tag = PALTAG_MISC},
|
|
{ .data = gSlotMachineReelTimeExplosion_Pal, .tag = PALTAG_EXPLOSION},
|
|
{ .data = gSlotMachineDigitalDisplay_Pal, .tag = PALTAG_DIG_DISPLAY},
|
|
{ .data = gSlotMachineMisc_Pal, .tag = PALTAG_PIKA_AURA},
|
|
{}
|
|
};
|
|
|
|
static const u32 sReelTimeGfx[] = INCBIN_U32("graphics/slot_machine/reel_time_gfx.4bpp.lz"); // reel_time_machine and reel_time_pikachu
|
|
static const u16 sReelTimeWindow_Tilemap[] = INCBIN_U16("graphics/slot_machine/reel_time_window.bin");
|
|
static const u16 sEmptyTilemap[] = {0};
|