/* --------------------------------------------------------------------- ** Project: Tetixx (a Tetris clone) ** File: thegame.c ** StartDate: 20.03.1999 ** Autor: Robert Jurziga */ #include #include "tetixx.h" // --------------------------------------------------------------------- // P R O T O T Y P E S // --------------------------------------------------------------------- void TheGame(); static void _comePlayField(); static void _goPlayField(); static void GameVSync(); static void _initPlayField(); static void _FadeUpGameField(void); static void _FadeDownGameField(void); unsigned short GetRandomStone(void); unsigned short GetRandomStoneClut(void); void Create_Preview_Stone(void); void Construct_Stone_Cords(unsigned char *shape, unsigned short *stoneinfo); void Current_Is_Preview(void); void DoGame(void); void Read_Functions(void); void Update_Game_Stone(void); short Flip_Current_Stone(void); inline short Apply_Stone(void); inline short Apply_Stone_Left(void); inline short Apply_Stone_Right(void); inline short Apply_Stone_Flip(void); inline short Apply_Stone_Down(void); void Render_Preview_Stone(void); void Render_Game_Stone(void); void Render_Tetixx_Field(void); void Render_Tetixx_Monitors(void); void New_Game_Stone(void); inline void Clear_Tetixx_Field(void); inline void Reset_Tetixx_Field_Sprites(void); inline void Reset_Tetixx_Monitor_Sprites(void); inline void Draw_Stone_Shape_In_Field(void); inline short Check_Lines(void); inline void Flush_Line(void); inline short Game_Over_Clear_Field(void); inline void Add_Up_Score(void); inline void Score_To_AscII(void); inline void Long_To_AscII(unsigned char *strbuf, unsigned long n); inline void Score_To_Sprite(void); inline void Set_Monitor_Sprites(unsigned char *str, GsSPRITE *gspr); inline void Flash_Score(void); void Game_Over_Score(void); // --------------------------------------------------------------------- // V A R I A B L E S // --------------------------------------------------------------------- int _ActiBuf; unsigned long _pressed; short _move_timeout; short _flip_timeout; short _down_timeout; short _ready; short _gameit; short _pause; short _pausecount; unsigned long _pauseshow; short _pauseOSP; short _game_over; short _fall_delay; short _flush_line_note; short _line_flag; short _drop_stone; short _bonus; unsigned long StoneCluts[]= { 768,253,16,1, 0x01090000,0x0d6c092a,0x15ae0842,0x1e118000, 0x26530400,0x3af832b6,0x477d435b,0x7fff4fbf, 768+16,253,16,1, 0x01070000,0x0d8b0948,0x15ed0842,0x1e2f8000, 0x26710400,0x3b162ef4,0x47bb4379,0x7fff4ffc, 768+32,253,16,1, 0x01040000,0x0d870946,0x15ea0842,0x1e2c8000, 0x266e0400,0x3b132ef1,0x47b74375,0x7fff4ff9, 768+48,253,16,1, 0x01010000,0x0d840943,0x15e60842,0x1e298000, 0x266a0400,0x3b0f2eed,0x47b34371,0x7fff4ff5, 768+64,253,16,1, 0x09000000,0x15830d42,0x1de50842,0x26278000, 0x2e690400,0x430e3aeb,0x53b14b70,0x7fff5bf3, 768+80,253,16,1, 0x15000000,0x21831942,0x29e50842,0x32278000, 0x3a690400,0x4f0e46eb,0x5fb15b70,0x7fff67f3, 768+96,253,16,1, 0x1d000000,0x2d832542,0x35e50842,0x42278000, 0x4a690400,0x5f0e56eb,0x6fb16b70,0x7fff77f3, 768+112,253,16,1, 0x20e00000,0x31632902,0x3d850842,0x45e78000, 0x4e290400,0x62ce5e8b,0x77716f30,0x7fff7f93, 768+128,253,16,1, 0x20800000,0x30e328c2,0x3d450842,0x45878000, 0x4dc90400,0x626e5e2b,0x76f16eb0,0x7fff7f33, 768+144,253,16,1, 0x20200000,0x30832862,0x3cc50842,0x45278000, 0x4d490400,0x61ee5dab,0x76716e30,0x7fff7eb3, 768+160,253,16,1, 0x20020000,0x30652843,0x3ca80842,0x44e98000, 0x4d2b0400,0x61d05d6e,0x76346e12,0x7fff7e76, 768+176,253,16,1, 0x20050000,0x30682846,0x3caa0842,0x44ec8000, 0x4d2e0400,0x61d35d71,0x76376e16,0x7fff7e79, 768+192,253,16,1, 0x20070000,0x306b2849,0x3cad0842,0x44f08000, 0x4d320400,0x61d75d75,0x763b6e1a,0x7fff7e7d, 768+208,253,16,1, 0x1c080000,0x2c6c204a,0x34af0842,0x3cf18000, 0x45330400,0x59d85177,0x6e3d661b,0x7fff727f, 768+224,253,16,1, 0x10080000,0x1c6c184a,0x28af0842,0x30f18000, 0x39330400,0x4dd84577,0x5e3d561b,0x7fff667f, 768+240,253,16,1, 0x04080000,0x106c0c4a,0x18af0842,0x24f18000, 0x29330400,0x3dd83577,0x4e3d461b,0x7fff567f, 768,254,16,1, 0x00480000,0x0cac086a,0x14ef0842,0x1d318000, 0x25730400,0x3a182dd7,0x469d425b,0x7fff4edf, 768+16,254,16,1, 0x00a80000,0x0d0c08ca,0x154f0842,0x1d918000, 0x25d30400,0x3a782e37,0x46fd42db,0x7fff4f3f, 768+32,254,16,1, 0x00e80000,0x0d6c092a,0x15af0842,0x1e118000, 0x26530400,0x3af82eb7,0x477d435b,0x7fff4fbf}; Stone_Rec BoxStone = { // BOX 0, 1, // step , steps {1, 1, 0, 0, // Shape 1 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, // shape 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, // shape 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, // shape 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; Stone_Rec TowerStone = { 0, 2, {0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 ,0}, {0, 0, 0, 0, // shape 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, // shape 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; Stone_Rec BlitzStone = { 0, 2, {1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; Stone_Rec Blitz2Stone = { 0, 2, {0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; Stone_Rec MidpinStone = { 0, 4, {1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, {0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0}, {1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; Stone_Rec TpinrStone = { 0, 4, {1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 ,0}, {1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; Stone_Rec TpinlStone = { 0, 4, {1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0}, {0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0 ,0, 0, 0, 0, 0} }; Stone_Rec DTPinrStone = { 0, 4, {1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, {0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0}, {1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; Stone_Rec TriStone = { 0, 4, {1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; Stone_Rec Mut1Stone = { 0, 4, {0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0}, {0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 ,0}, {1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0} }; Stone_Rec CrossStone = { 0, 1, {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; Stone_Rec LoTowerStone = { 0, 2, {0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; unsigned char *TStones[]= { (unsigned char *)&BoxStone, (unsigned char *)&TowerStone, (unsigned char *)&BlitzStone, (unsigned char *)&Blitz2Stone, (unsigned char *)&MidpinStone, (unsigned char *)&TpinrStone, (unsigned char *)&TpinlStone, (unsigned char *)&DTPinrStone, (unsigned char *)&TriStone, (unsigned char *)&Mut1Stone, (unsigned char *)&CrossStone, (unsigned char *)&LoTowerStone }; unsigned short PreviewStone[32]; unsigned char *PreviewStoneShape; GsSPRITE PreviewStoneSprites[16]; unsigned short PreviewStoneSprCount; unsigned short prevstone; unsigned short prevclutx; unsigned short prevcluty; unsigned short prevtotal_w, prevtotal_h; unsigned short CurrStone[32]; unsigned char *CurrStoneShape; GsSPRITE CurrStoneSprites[16]; unsigned short CurrStoneSprCount; unsigned short currstone; unsigned short currclutx; unsigned short currcluty; unsigned short currtotal_w, currtotal_h; unsigned short stone_xoff, stone_yoff, stone_mxoff, stone_myoff; unsigned short stone_xsize, stone_ysize; GsSPRITE *SpriteLineToFlush; short WhichLineToFlush,WhichLineToFlushCtrl,WhichLineToFlushGameOver; unsigned long CurrentHiscore; unsigned long ScoreToAdd; unsigned long LinesScore; unsigned long DropScore; short HiscoreBeaten; short HiscoreBeatenFlag; unsigned char GameHiScoreDec[10]; unsigned char GameScoreDec[10]; unsigned char GameLinesDec[10]; unsigned char GameStonesDec[10]; unsigned char GameTimeDec[6]; unsigned char DecTemp[10]; GsSPRITE GameScoreSprites[9]; GsSPRITE GameLinesSprites[9]; GsSPRITE GameStonesSprites[9]; GsSPRITE GameHiScoreSprites[9]; GsSPRITE GameTimeSprites[8]; unsigned char NumbersVRAM_UV[22]; unsigned long TempScore_Lines, TempScore_Stones, TempScore_Time; unsigned char TetixxField[TETIXX_FIELD_SIZE]; GsSPRITE TetixxFieldSprites[TETIXX_FIELD_SPRITES]; /* --------------------------------------------------------------------- // Function: TheGame // Description: Here it the "Tetixx Game Engine" */ void TheGame() { ResetYXM(&IngameMod, 0); _ready=0; _initPlayField(); _comePlayField(); _ready=1; SsUtKeyOn(GameSfxVabID, 0, GSFX_START_GAME, 42, 0, 127, 127); srand(GetRCnt(1)); DoGame(); _ready=0; _goPlayField(); if (check_hs_entry) DoHiscore(1); else _goPlayField(); } /* --------------------------------------------------------------------- ** Function: GameVSync */ static void GameVSync() { unsigned char mask; _ActiBuf = GsGetActiveBuff(); PadBits=(~(*(pport0+2) | *(pport0+3) << 8 )); mask = *(pport0+1) >> 4; if (*pport0 == 0xff || mask != 0x4) InsertStandardController(&ThemeMod); GsSetWorkBase((PACKET*)GPU_WorkArea[_ActiBuf]); GsClearOt(0, 0, &WorldOT[_ActiBuf]); if (_pause) { GsSortFastSprite(&PauseLogoSprite,&WorldOT[_ActiBuf],0); if (_pause == 4) { _pause = 0; ResetYXM(&IngameMod, _pauseOSP); } else { _pausecount++; if (_pausecount > 20) { _pausecount=0; _pauseshow^=(1<<31); PauseLogoSprite.attribute=_pauseshow; if (!_pauseshow) SsUtKeyOn(IngameMod.yxmd_vabid, 0, 4, 50, 0, 127, 127); } } } else { GsSortFastSprite(&BGLeft,&WorldOT[_ActiBuf],15); // render background GsSortFastSprite(&BGRight,&WorldOT[_ActiBuf],15); GsSortFastSprite(&PlayBackTextSprite,&WorldOT[_ActiBuf],14); GsSortFastSprite(&GameScoreMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&GameLinesMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&GameStonesMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&GameTimeMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&PreviewMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&HiscoreMonitorSprite,&WorldOT[_ActiBuf],13); if (_gameit) { if (!_game_over) { GsSortFastSprite(&GameCtrlIngameSprite,&WorldOT[_ActiBuf],13); Render_Preview_Stone(); Render_Game_Stone(); Render_Tetixx_Field(); Render_Tetixx_Monitors(); CurrentGameHS.he_playtime++; } else { if (_bonus) { GsSortFastSprite(&GameOverLogoSprite,&WorldOT[_ActiBuf],13); } else { GsSortFastSprite(&BonusLogoSprite, &WorldOT[_ActiBuf],13); } Render_Tetixx_Field(); Render_Tetixx_Monitors(); } } PlayYXM(&IngameMod); } DrawSync(0); VSync(0); GsSwapDispBuff(); GsSortClear(0x0, 0x0, 0x0, &WorldOT[_ActiBuf]); GsDrawOt(&WorldOT[_ActiBuf]); } /* --------------------------------------------------------------------- ** Function: _initPlayField */ static void _initPlayField() { GsSPRITE *spr; // set PlayBackground coords to come spr = &PlayBackTextSprite; spr-> x = 0 - 232; spr-> y = 0 + 16; spr->r = spr->g = spr->b = 64; // set Game Monitor sprites to come spr = &PreviewMonitorSprite; spr-> x = 520; spr-> y = 0 + 16; spr->r = spr->g = spr->b = 64; spr = &GameScoreMonitorSprite; spr-> x = 520; spr-> y = 75 + 16; spr->r = spr->g = spr->b = 64; spr = &HiscoreMonitorSprite; spr-> x = 520 + 112; spr-> y = 75 + 16; spr->r = spr->g = spr->b = 64; spr = &GameLinesMonitorSprite; spr-> x = 520; spr-> y = 75 + 16 + 48; spr->r = spr->g = spr->b = 64; spr = &GameStonesMonitorSprite; spr-> x = 520+112; spr-> y = 75 + 16 + 48; spr->r = spr->g = spr->b = 64; spr = &GameTimeMonitorSprite; spr-> x = 520; spr-> y = 75 + 16 + 96; spr->r = spr->g = spr->b = 64; // set Game Control Sprite Offsets spr = &BonusLogoSprite; spr->x = 512 - 113; spr->y = 256 - 42; spr = &GameCtrlIngameSprite; spr->x = 512 - 140; spr->y = 256 - 70; // center pause Logo spr= &PauseLogoSprite; spr->x = ((512 - 136)>>1); spr->y = ((256 - 24)>>1); // Game over logo positons spr=&GameOverLogoSprite; spr->x = (512 - 160); spr->y = (256 - 42); } /* --------------------------------------------------------------------- ** Function: _comePlayField */ static void _comePlayField() { GsSPRITE *spr; spr = &PlayBackTextSprite; while (spr->x < 8) { PreviewMonitorSprite.x-=9; HiscoreMonitorSprite.x-=9; GameScoreMonitorSprite.x-=9; GameLinesMonitorSprite.x-=9; GameStonesMonitorSprite.x-=9; GameTimeMonitorSprite.x-=9; spr->x+=8; GsSortFastSprite(spr,&WorldOT[_ActiBuf],14); GsSortFastSprite(&GameScoreMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&GameLinesMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&GameStonesMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&GameTimeMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&PreviewMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&HiscoreMonitorSprite,&WorldOT[_ActiBuf],13); GameVSync(); } } /* --------------------------------------------------------------------- ** Function: _goPlayField() */ static void _goPlayField() { GsSPRITE *spr; spr = &PlayBackTextSprite; while (spr->x > -232) { PreviewMonitorSprite.x+=9; HiscoreMonitorSprite.x+=9; GameScoreMonitorSprite.x+=9; GameLinesMonitorSprite.x+=9; GameStonesMonitorSprite.x+=9; GameTimeMonitorSprite.x+=9; spr->x-=8; GsSortFastSprite(spr,&WorldOT[_ActiBuf],14); GsSortFastSprite(&GameScoreMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&GameLinesMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&GameStonesMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&GameTimeMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&PreviewMonitorSprite,&WorldOT[_ActiBuf],13); GsSortFastSprite(&HiscoreMonitorSprite,&WorldOT[_ActiBuf],13); GameVSync(); } } /* ---------------------------------- ** Function: _FadeUpGameField ** Description: Fadeup the game field gfx. */ static void _FadeUpGameField(void) { GsSPRITE *spr; while(1) { spr = &PlayBackTextSprite; spr->r = spr->g = spr->b+=4; spr = &PreviewMonitorSprite; spr->r = spr->g = spr->b+=4; spr = &GameScoreMonitorSprite; spr->r = spr->g = spr->b+=4; spr = &HiscoreMonitorSprite; spr->r = spr->g = spr->b+=4; spr = &GameLinesMonitorSprite; spr->r = spr->g = spr->b+=4; spr = &GameStonesMonitorSprite; spr->r = spr->g = spr->b+=4; spr = &GameTimeMonitorSprite; spr->r = spr->g = spr->b+=4; GameVSync(); if (spr->r == 128) break; } } /* ------------------------------------- ** Function: _FadeDownGameField ** Description: Fade down the game field gfx. */ static void _FadeDownGameField(void) { GsSPRITE *spr; while(1) { spr = &PlayBackTextSprite; spr->r = spr->g = spr->b-=4; spr = &PreviewMonitorSprite; spr->r = spr->g = spr->b-=4; spr = &GameScoreMonitorSprite; spr->r = spr->g = spr->b-=4; spr = &HiscoreMonitorSprite; spr->r = spr->g = spr->b-=4; spr = &GameLinesMonitorSprite; spr->r = spr->g = spr->b-=4; spr = &GameStonesMonitorSprite; spr->r = spr->g = spr->b-=4; spr = &GameTimeMonitorSprite; spr->r = spr->g = spr->b-=4; GameVSync(); if (spr->r == 64) break; } } /* --------------------------------------------------------------------- ** Function: GetRandomStone ** Description: Get randomized stone shape number. */ unsigned short GetRandomStone(void) { unsigned int val; val = rand(); return(val % STONE_NUMBER); } /* --------------------------------------------------------------------- ** Function: GetRandomStoneClut ** Description: Get randomized stone clut number. */ unsigned short GetRandomStoneClut(void) { unsigned int val; val = rand(); return(val % STONE_CLUT_NUMBER); } /* --------------------------------------------------------------------- ** Function: Construct_Stone_Cords ** Description: Construct the stone coords according to the shape */ void Construct_Stone_Cords(unsigned char *shape, unsigned short *stoneinfo) { unsigned char *shapeptr; unsigned short xoff,yoff,i,j; unsigned short *cords; unsigned short shapestep; xoff = yoff = 0; shapeptr=shape; shapestep = (unsigned short)*shapeptr; shapeptr+=2; shapeptr+=(shapestep << 4); // point to real shape cords=(unsigned short *)stoneinfo; for(i=0; i<4;i++) { for(j=0; j<4; j++) { if (*shapeptr) { *cords=xoff; *(cords+1)=yoff; } else { *cords= 0xffff; *(cords+1)= 0xffff; } cords+=2; shapeptr++; xoff+=STONE_WIDTH; } xoff=0; yoff+=STONE_HEIGHT; } } /* --------------------------------------------------------------------- ** Function: Create_Preview_Stone ** Description: Get randoms of shape and clut then construct ** shape. */ void Create_Preview_Stone(void) { unsigned short total_w,total_h,xoff,yoff,clut; unsigned long *clutarray; unsigned char *shapeptr; short cx,cy,i; GsSPRITE *spr; unsigned short *preview; prevstone = GetRandomStone(); clut = GetRandomStoneClut(); clutarray = &StoneCluts[0]; clutarray+=(clut * 12); prevclutx = cx = (short)*clutarray++; prevcluty = cy = (short)*clutarray; shapeptr = TStones[prevstone]; PreviewStoneShape = shapeptr; *shapeptr=0x0; Construct_Stone_Cords(PreviewStoneShape, &PreviewStone[0]); // ==== get total width and height preview = &PreviewStone[0]; total_w = total_h = 0; for(i=0; i<16; i++, preview+=2) { if (*preview != 0xffff) { if (total_w < *preview) total_w = *preview; if (total_h < *(preview+1)) total_h = *(preview+1); } } total_w+=STONE_WIDTH; total_h+=STONE_HEIGHT; prevtotal_w = total_w; prevtotal_h = total_h; if (prevstone == 1 || prevstone == 11) total_w+=STONE_WIDTH; xoff=((PREVIEW_MONITOR_WIDTH-total_w) >> 1) + PREVIEW_MONITOR_LEFT; yoff=((PREVIEW_MONITOR_HEIGHT-total_h) >> 1) + PREVIEW_MONITOR_TOP; PreviewStoneSprCount=0; spr = &PreviewStoneSprites[0]; preview = &PreviewStone[0]; for(i=0; i<16; i++, preview+=2) { if (*preview != 0xffff) { spr->x = (xoff + *preview); spr->y = (yoff + *(preview+1)); spr->cx = cx; spr->cy = cy; PreviewStoneSprCount++; spr++; } } } /* --------------------------------------------------------------------- ** Function: Current_Is_Preview ** Description: Copy whole PreviewStone Data into the Current Stone ** Data. */ void Current_Is_Preview(void) { short i; unsigned short *src,*dest; GsSPRITE *srcspr, *destspr; currstone = prevstone; currclutx = prevclutx; currcluty = prevcluty; CurrStoneShape = PreviewStoneShape; CurrStoneSprCount = PreviewStoneSprCount; currtotal_w = prevtotal_w; currtotal_h = prevtotal_h; // ---- copy stone offset table src=&PreviewStone[0]; dest=&CurrStone[0]; for (i=0; i<32; i++, src++, dest++) { *dest=*src; } // ---- copy spr->cx /cy infons destspr=&CurrStoneSprites[0]; srcspr=&PreviewStoneSprites[0]; for (i=0; icx = srcspr->cx; destspr->cy = srcspr->cy; } } /* --------------------------------------------------------------------- ** Function: Clear_Tetixx_Field ** Description: Set the Tetixx field like this: ** 1, 0, 0, ... STONE IN ROW, 1 ** 1, 0, ... ** . ** STONES_ROWS ** 1, 1, 1, 1, 1, 1, 1, ......1 ** */ inline void Clear_Tetixx_Field(void) { // .set at asm ("la $8,TetixxField li $9,1 li $10,18 ctf_loop: li $11,11 sb $9,0($8) addiu $8,$8,1 ctf_loop1: sb $0,0($8) addiu $8,$8,1 addi $11,$11, -1 bne $11,$0,ctf_loop1 sb $9,0($8) addiu $8,$8, 1 addi $10,$10, -1 bne $10,$0,ctf_loop li $10,11+2 ctf_loop2: sb $9,0($8) addiu $8,$8,1 addi $10,$10,-1 bne $10,$0,ctf_loop2 "); // jr ra } /* --------------------------------------------------------------------- ** Function: Reset_Tetixx_Field_Sprites ** Description: */ inline void Reset_Tetixx_Field_Sprites(void) { typedef GsSPRITE spr; // .set reorder asm ("la $8,TetixxFieldSprites li $9,0x88000000 li $10,28 li $11,18 li $14,128 rtfs_loop0: li $12,11 li $13,16 rtfs_loop1: sw $9,0($8) sh $10,6($8) sh $13,4($8) sb $14,20($8) sb $14,21($8) sb $14,22($8) addiu $13,$13,20 addi $12,$12, -1 addiu $8,$8,36 bne $12,$0,rtfs_loop1 addiu $10,$10,12 addi $11,$11,-1 bne $11,$0,rtfs_loop0 "); // jr ra } /* --------------------------------------------------------------------- ** Function: Reset_Tetixx_Monitor_Sprites ** Description: */ inline void Reset_Tetixx_Monitor_Sprites(void) { typedef GsSPRITE spr; // .set reorder asm ("la $8,GameTimeSprites la $9,NumbersVRAM_UV lbu $12,0($9) lbu $13,1($9) lbu $14,20($9) lbu $15,21($9) li $3,3 rtms_Reset_Time_Loop: sw $0,0($8) sb $12,14($8) sb $13,15($8) addiu $8,$8,36 sw $0,0($8) sb $12,14($8) sb $13,15($8) addiu $8,$8,36 addi $3,$3,-1 nop beq $3,$0,rtms_Reset_Score sw $0,0($8) sb $14,14($8) sb $15,15($8) addiu $8,$8,36 j rtms_Reset_Time_Loop rtms_Reset_Score: la $8,GameScoreSprites li $3,8 li $10,0x88000000 li $11,128 sw $0,0($8) sb $12,14($8) sb $13,15($8) sb $11,20($8) sb $11,21($8) sb $11,22($8) addiu $8,$8,36 rtms_Reset_Score_Loop: sw $10,0($8) sb $11,20($8) sb $11,21($8) sb $11,22($8) addi $3,$3, -1 addiu $8,$8,36 bne $3,$0,rtms_Reset_Score_Loop la $8,GameHiScoreSprites li $3,8 sw $0,0($8) sb $12,14($8) sb $13,15($8) addiu $8,$8,36 rtms_Reset_Hiscore_Loop: sw $10,0($8) addi $3,$3,-1 addiu $8,$8,36 bne $3,$0,rtms_Reset_Hiscore_Loop la $8,GameLinesSprites li $3,8 sw $0,0($8) sb $12,14($8) sb $13,15($8) addiu $8,$8,36 rtms_Reset_Lines_Loop: sw $10,0($8) addi $3,$3,-1 addiu $8,$8,36 bne $3,$0,rtms_Reset_Lines_Loop la $8,GameStonesSprites li $3,8 sw $0,0($8) sb $12,14($8) sb $13,15($8) addiu $8,$8,36 rtms_Reset_Stones_Loop: sw $10,0($8) addi $3,$3,-1 addiu $8,$8,36 bne $3,$0,rtms_Reset_Stones_Loop "); // jr ra } /* --------------------------------------------------------------------- ** Function: New_Game_Stone ** Description: Set up cordinates for new stone. Check if the stone ** fits in the Field. Check if overlaping other stone. ** If yes GAME OVER. */ void New_Game_Stone(void) { unsigned short xoff; xoff = ((STONES_IN_ROW - (currtotal_w / 20)) >> 1); stone_xoff = TETIXX_FIELD_XOFF + (xoff * 20); stone_mxoff = xoff; stone_yoff = TETIXX_FIELD_YOFF; stone_myoff = 0; stone_xsize = (currtotal_w / 20); stone_ysize = (currtotal_h / 12); _game_over = Apply_Stone(); } /* ====================================================================== ** Function: Do Game ** Description: Here is the game so far */ void DoGame(void) { _FadeUpGameField(); // initalize game data CurrentGameHS.he_score = 0; CurrentGameHS.he_lines = 0; CurrentGameHS.he_stones = 0; CurrentGameHS.he_playtime = 0; CurrentHiscore=HiscoreList[0].he_score; ScoreToAdd = 0; HiscoreBeaten = HiscoreBeatenFlag = 0; DropScore=SCORE_DROP; _move_timeout = _flip_timeout = _down_timeout = 0; _game_over = _pressed = _bonus = _pause = _line_flag = _drop_stone = _pause = 0; _gameit = 1; _fall_delay = 30; // Inititialize Game Create_Preview_Stone(); Current_Is_Preview(); Create_Preview_Stone(); Clear_Tetixx_Field(); Reset_Tetixx_Field_Sprites(); Reset_Tetixx_Monitor_Sprites(); New_Game_Stone(); while(1) { if (_game_over) { if (_line_flag) Flush_Line(); if (Game_Over_Clear_Field()) break; } else { if (_pause) { switch (_pause) { case 1: { if (!(PadBits & 0xffff)) _pause++; break; } case 2: { if (PadBits & PAD_Start) _pause++; break; } case 3: { if (!(PadBits & 0xffff)) _pause++; break; } } } else { if (!_drop_stone) Read_Functions(); if (!_fall_delay) { if(Apply_Stone_Down()) { stone_myoff++; stone_yoff+=12; DropScore-=99; } else { _drop_stone=0; ScoreToAdd+=SCORE_STONE_PUT; DropScore=SCORE_DROP; SsUtKeyOn(GameSfxVabID, 0, GSFX_PUT, 42, 0, 127, 127); Draw_Stone_Shape_In_Field(); Current_Is_Preview(); Create_Preview_Stone(); New_Game_Stone(); if (_game_over) { SsUtKeyOn(GameSfxVabID, 0, GSFX_GAME_OVER, 42, 0, 127, 127); WhichLineToFlushGameOver = 18; //( the last line) WhichLineToFlushCtrl = 0; // used for flag } else CurrentGameHS.he_stones++; } if (_drop_stone) _fall_delay = 2; else _fall_delay = 30; } _fall_delay--; if (_line_flag) { Flush_Line(); } else { _line_flag = Check_Lines(); if (_line_flag) { SsUtKeyOn(GameSfxVabID, 0, GSFX_LINE_GONE, _flush_line_note, 0, 127, 127); CurrentGameHS.he_lines++; ScoreToAdd+=SCORE_FLUSH_LINE; } } Update_Game_Stone(); } // if (PadBits & PAD_Select) dumpScreen(0, 0, 511, 256); } Add_Up_Score(); Score_To_AscII(); Score_To_Sprite(); Flash_Score(); GameVSync(); } _bonus = 1; Game_Over_Score(); StopYXM(&IngameMod); _gameit=0; _FadeDownGameField(); } /* --------------------------------------------------------------------- ** Function: Read_Functions ** Description: Read the joypad in the game loop */ void Read_Functions(void) { if (PAD_Cross & PadBits) { if (PAD_Cross & _pressed) { _flip_timeout++; if (_flip_timeout == TIME_OUT_FLIP) _pressed^=PAD_Cross; } else { _pressed|=PAD_Cross; _flip_timeout=0; if (Flip_Current_Stone()) SsUtKeyOn(GameSfxVabID, 0, GSFX_FLIP, 42, 0, 127, 127); else SsUtKeyOn(ChooseSoundVabID, 0, SFX_ILLEGAL, 45, 0, 100, 100); } } else _pressed&=~PAD_Cross; if (PAD_Left & PadBits) { if (PAD_Left & _pressed) { _move_timeout++; if (_move_timeout == TIME_OUT_MOVE) _pressed^=PAD_Left; } else { _pressed|=PAD_Left; _move_timeout=0; if (Apply_Stone_Left()) { stone_xoff-=20; stone_mxoff--; } } } else _pressed&=~PAD_Left; if (PAD_Right & PadBits) { if (PAD_Right & _pressed) { _move_timeout++; if (_move_timeout == TIME_OUT_MOVE) _pressed^=PAD_Right; } else { _pressed|=PAD_Right; _move_timeout = 0; if (Apply_Stone_Right()) { stone_xoff+=20; stone_mxoff++; } } } else _pressed&=~PAD_Right; if (PAD_Down & PadBits) { if (PAD_Down & _pressed) { _down_timeout++; if (_down_timeout == TIME_OUT_DOWN) _pressed^=PAD_Down; } else { _pressed|=PAD_Down; _fall_delay = _down_timeout=0; ScoreToAdd+=SCORE_DOWN; } } else _pressed&=~PAD_Down; if ((_pressed & PAD_Circle)) { if (!(PadBits & 0xffff)) _pressed&=~PAD_Circle; } else { if (PAD_Circle & PadBits) { _pressed|=PAD_Circle; _drop_stone=1; _fall_delay=2; SsUtKeyOn(GameSfxVabID, 0, GSFX_DROP, 42, 0, 127, 127); ScoreToAdd+=DropScore; } } if (PAD_Triangle & PadBits) { SsUtKeyOn(ChooseSoundVabID, 0, SFX_GO_BACK, 50, 0, 127, 127); _game_over = 1; SsUtKeyOn(GameSfxVabID, 0, GSFX_GAME_OVER, 42, 0, 127, 127); WhichLineToFlushGameOver = 18; WhichLineToFlushCtrl = 0; } if (PAD_Start & PadBits) { _pause=1; _pausecount=0; _pauseshow=0; PauseLogoSprite.attribute=0; _pauseOSP = StopYXM(&IngameMod); SsUtKeyOn(IngameMod.yxmd_vabid, 0, 4, 40, 0, 127, 127); } } /* --------------------------------------------------------------------- ** Function: Render_Preview_Stone ** Description: Render the next stone to come into the PreviewMonitor */ void Render_Preview_Stone(void) { GsSPRITE *spr; short i; spr = &PreviewStoneSprites[0]; for(i=0; iattribute != onoff) GsSortFastSprite(spr,&WorldOT[_ActiBuf],12); } } /* --------------------------------------------------------------------- ** Function: Render_Tetixx_Monitors ** Description: Render the next stone to come into the PreviewMonitor */ void Render_Tetixx_Monitors(void) { unsigned long onoff = 0x88000000; short i; GsSPRITE *spr; spr=&GameScoreSprites[0]; for (i=0; i<9; i++, spr++) { if (spr->attribute != onoff) GsSortFastSprite(spr,&WorldOT[_ActiBuf],11); } spr=&GameHiScoreSprites[0]; for (i=0; i<9; i++, spr++) { if (spr->attribute != onoff) GsSortFastSprite(spr,&WorldOT[_ActiBuf],11); } spr=&GameLinesSprites[0]; for (i=0; i<9; i++, spr++) { if (spr->attribute != onoff) GsSortFastSprite(spr,&WorldOT[_ActiBuf],11); } spr=&GameStonesSprites[0]; for (i=0; i<9; i++, spr++) { if (spr->attribute != onoff) GsSortFastSprite(spr,&WorldOT[_ActiBuf],11); } spr=&GameTimeSprites[0]; for (i=0; i<8; i++, spr++) { if (spr->attribute != onoff) GsSortFastSprite(spr,&WorldOT[_ActiBuf],11); } } /* --------------------------------------------------------------------- ** Function: Update_Game_Stone ** Description: Set up a game stone according to the current. */ void Update_Game_Stone(void) { unsigned short xoff,i,yoff; GsSPRITE *spr; unsigned short *cords; xoff = stone_xoff; yoff = stone_yoff; spr=&CurrStoneSprites[0]; cords = &CurrStone[0]; CurrStoneSprCount=0; for(i=0; i<16; i++, cords+=2) { if (*cords != 0xffff) { spr->x = xoff + *cords; spr->y = yoff + *(cords+1); spr++; CurrStoneSprCount++; } } } /* --------------------------------------------------------------------- ** Function: Flip_Current_Stone ** Description: Flip stone. Increase the step */ short Flip_Current_Stone(void) { short ret = 0; if (Apply_Stone_Flip()) { Construct_Stone_Cords(CurrStoneShape, &CurrStone[0]); ret = 1; } return(ret); } /* --------------------------------------------------------------------- ** Function: Apply_Stone ** Description: Check if new stone is not overlaping with other stones ** If its so GAME OVER. */ inline short Apply_Stone(void) { // .set reorder asm (" lw $8,CurrStoneShape la $9,TetixxField sb $0,0($8) addiu $8,$8,2 lh $10,stone_mxoff addu $9,$10,$9 addiu $9,$9,1 li $13,4 as_loop0: li $14,4 move $10,$9 as_loop1: lbu $11,0($8) lbu $12,0($10) nop beq $11,$0,as_c0 nop bne $12,$0,as_game_over nop as_c0: addiu $8,$8,1 addiu $10,$10,1 addi $14,$14,-1 bne $14,$0,as_loop1 nop addiu $9,$9,11+2 addi $13,$13,-1 bne $13,$0,as_loop0 nop li $2,0 j asxx as_game_over: li $2,1 asxx: "); // jr ra } /* --------------------------------------------------------------------- ** Function: Apply_Stone_Left ** Description: Check if moving to left is allowed. ** If move is allowed return 1 ** If not return 0 */ inline short Apply_Stone_Left(void) { // .set reorder asm ("lw $8,CurrStoneShape la $9,TetixxField lbu $10,0($8) addiu $8,$8,2 sll $10,$10, 4 addu $8,$8,$10 lh $10,stone_mxoff lhu $11,stone_myoff addi $10,$10,1 li $3,11+2 multu $3,$11 nop nop mflo $11 addu $9,$9,$11 addu $9,$9,$10 li $11,4 asl_loop0: li $12,4 move $13,$9 move $14,$8 asl_loop1: lbu $24,0($14) nop beq $24,$0,asl_c0 nop lbu $25,-1($13) nop bne $25,$0,asl_not_allowed nop j asl_n0 asl_c0: addiu $13,$13,1 addiu $14,$14,1 addi $12,$12,-1 bne $12,$0,asl_loop1 nop asl_n0: addiu $8,$8,4 addiu $9,$9,11+2 addi $11,$11,-1 bne $11,$0,asl_loop0 nop li $2,1 j aslxx asl_not_allowed: move $2,$0 aslxx: "); // jr ra } /* --------------------------------------------------------------------- ** Function: Apply_Stone_Right ** Description: Check if moving to right is allowed. ** If move is allowed return 1 ** If not return 0 */ inline short Apply_Stone_Right(void) { // .set reorder asm ("lw $8,CurrStoneShape la $9,TetixxField lbu $10,0($8) addiu $8,$8,2 sll $10,$10,4 addu $8,$8,$10 lh $10,stone_mxoff lhu $11,stone_myoff addi $10,$10,1 li $3,11+2 multu $3,$11 nop nop mflo $11 addu $9,$9,$11 addu $9,$9,$10 addiu $8,$8,3 addiu $9,$9,3 li $11,4 asr_loop0: li $12,4 move $13,$9 move $14,$8 asr_loop1: lbu $24,0($14) nop beq $24,$0,asr_c0 nop lbu $25,1($13) nop bne $25,$0,asr_not_allowed nop j asr_n0 asr_c0: addi $13,$13,-1 addi $14,$14,-1 addi $12,$12,-1 bne $12,$0,asr_loop1 nop asr_n0: addiu $8,$8,4 addiu $9,$9,11+2 addi $11,$11,-1 bne $11,$0,asr_loop0 nop li $2,1 j asrxx asr_not_allowed: move $2,$0 asrxx: "); // jr ra } /* --------------------------------------------------------------------- ** Function: Apply_Stone_Flip ** Description: Check if stone can be flipped. */ inline short Apply_Stone_Flip(void) { // .set reorder asm (" lw $8,CurrStoneShape lbu $24,0($8) lbu $25,1($8) nop addiu $24,$24,1 bne $24,$25,asf_c0 nop move $24,$0 asf_c0: addiu $9,$8,2 sll $10,$24,4 addu $9,$9,$10 la $10,TetixxField lh $11,stone_mxoff lhu $12,stone_myoff addi $11,$11,1 li $3,11+2 multu $3,$12 nop nop mflo $12 addu $10,$10,$12 addu $10,$10,$11 li $11,4 asf_loop0: li $12,4 move $13,$10 asf_loop1: lbu $14,0($9) lbu $15,0($13) nop beq $14,$0,asf_n0 nop bne $15,$0,asf_no_flip nop asf_n0: addiu $9,$9,1 addiu $13,$13,1 addi $12,$12,-1 bne $12,$0,asf_loop1 nop addiu $10,$10,11+2 addi $11,$11,-1 bne $11,$0,asf_loop0 nop sb $24,0($8) li $2,1 j asfxx asf_no_flip: move $2,$0 asfxx: "); // jr ra } /* --------------------------------------------------------------------- ** Function: Apply_Stone_Down ** Description: Check the stone bottom form bottom to top */ inline short Apply_Stone_Down(void) { // .set reorder asm ("lw $8,CurrStoneShape lbu $9,0($8) sll $9,$9,4 addiu $9,$9,2 addu $8,$8,$9 la $9,TetixxField lh $10,stone_mxoff lhu $11,stone_myoff addi $10,$10,1 addiu $11,$11,3 li $3,11+2 multu $3,$11 nop nop mflo $11 addu $9,$9,$11 addu $9,$9,$10 addiu $8,$8,12 li $10,4 asd_loop0: li $11,4 move $13,$8 move $14,$9 asd_loop1: lbu $15,0($13) nop beq $15,$0,asd_c0 nop lbu $24,11+2($14) nop bne $24,$0,asd_put_stone nop j asd_n0 asd_c0: addi $13,$13,-4 addi $14,$14,-(11+2) addi $11,$11,-1 bne $11,$0,asd_loop1 nop asd_n0: addiu $8,$8,1 addiu $9,$9,1 addi $10,$10,-1 bne $10,$0,asd_loop0 nop li $2,1 j asdxx asd_put_stone: move $2,$0 asdxx: "); // jr ra } /* --------------------------------------------------------------------- ** Function: Draw_Stone_Shape_In_Field ** Description: If stone reached bottom or other stone draw the shape ** into the field and activate the sprites. */ inline void Draw_Stone_Shape_In_Field(void) { typedef GsSPRITE spr; // .set reorder asm (" lw $8,CurrStoneShape la $9,TetixxField la $10,TetixxFieldSprites lbu $11,0($8) sll $11,$11,4 addiu $8,$8,2 addu $8,$8,$11 lh $11,stone_mxoff lhu $12,stone_myoff addi $11,$11,1 li $3,11+2 multu $3,$12 nop nop mflo $13 addu $9,$9,$13 addu $9,$9,$11 li $3,36 addi $11,$11,-1 multu $3,$11 li $13,11 nop mflo $11 addu $10,$10,$11 multu $13,$3 nop nop mflo $11 multu $12,$11 nop nop mflo $12 addu $10,$10,$12 lhu $2,currclutx lhu $3,currcluty li $13,4 dssif_loop0: li $14,4 move $15,$9 move $24,$10 dssif_loop1: lbu $25,0($8) nop beq $25,$0,dssif_c0 nop sb $25,0($15) sw $0,0($24) sh $2,16($24) sh $3,18($24) dssif_c0: addiu $8,$8,1 addiu $15,$15,1 addiu $24,$24,36 addi $14,$14,-1 bne $14,$0,dssif_loop1 nop addiu $9,$9,11+2 addu $10,$10,$11 addi $13,$13,-1 bne $13,$0,dssif_loop0 nop "); // jr ra } /* --------------------------------------------------------------------- ** Function: Check_Lines ** Description: Test if lines are completed. */ inline short Check_Lines(void) { typedef GsSPRITE spr; // .set reorder asm (" la $8,TetixxField li $3,11 move $25,$0 li $9,18 cl_loop0: li $10,11 addiu $8,$8,1 move $11,$0 cl_loop1: lbu $12,0($8) nop addu $11,$11,$12 addiu $8,$8,1 addi $10,$10,-1 bne $10,$0,cl_loop1 nop beq $11,$3,cl_Line_Found nop addiu $25,$25,1 addiu $8,$8,1 addi $9,$9,-1 bne $9,$0,cl_loop0 nop li $3,34 sh $3,_flush_line_note sw $0,LinesScore sh $0,WhichLineToFlush move $2,$0 j cl_x cl_Line_Found: li $3,36 li $9,11 multu $3,$9 nop nop mflo $9 multu $25,$9 nop nop mflo $12 la $10,TetixxFieldSprites addu $10,$10,$12 sw $10,SpriteLineToFlush sh $25,WhichLineToFlush li $11,255 li $13,0x60000000 li $12,11 cl_SetSprite_RGB: sw $13,0($10) sb $11,20($10) sb $11,21($10) sb $11,22($10) addiu $10,$10,36 addi $12,$12,-1 bne $12,$0,cl_SetSprite_RGB nop addi $8,$8,-(11+1) beq $25,$0,cl_Clear_Line nop addi $25,$25,-1 j cl_Remap_Field nop cl_Clear_Line: li $9,11 cl_Clear_Line_Loop: sb $0,1($8) nop addiu $8,$8,1 addi $9,$9,-1 nop bne $9,$0,cl_Clear_Line_Loop nop j cl_Leave nop cl_Remap_Field: addi $9,$8,-(11+2) cl_Remap_Field_Loop: lbu $10,0($9) lbu $11,1($9) lbu $12,2($9) lbu $13,3($9) lbu $14,4($9) lbu $15,5($9) lbu $24,6($9) sb $10,0($8) sb $11,1($8) sb $12,2($8) sb $13,3($8) sb $14,4($8) sb $15,5($8) sb $24,6($8) lbu $10,7($9) lbu $11,8($9) lbu $12,9($9) lbu $13,10($9) lbu $14,11($9) lbu $15,12($9) sb $10,7($8) sb $11,8($8) sb $12,9($8) sb $13,10($8) sb $14,11($8) sb $15,12($8) addi $25,$25,-1 addiu $8,$8,-(11+2) addiu $9,$9,-(11+2) slti $3,$25,0 beq $3,$0,cl_Remap_Field_Loop nop j cl_Clear_Line nop cl_Leave: lhu $3,_flush_line_note addiu $3,$3,2 sh $3,_flush_line_note lw $3,LinesScore lw $8,ScoreToAdd addu $8,$8,$3 sw $8,ScoreToAdd addiu $3,$3,2999 sw $3,LinesScore li $2,1 cl_x: "); // jr ra } /* --------------------------------------------------------------------- ** Function: Flush_Line ** Description: Fade down the line sprite RGB fast. Then Remap sprites */ inline void Flush_Line(void) { typedef GsSPRITE spr; // .set reorder asm ("lw $8,SpriteLineToFlush li $9,11 lb $10,20($8) nop beq $10,$0,fl_Remap_Sprites nop fl_loop0: lbu $10,20($8) lbu $11,21($8) lbu $12,22($8) addi $10,$10,-24 addi $11,$11,-24 addi $12,$12,-24 bgtz $10,fl_c0 nop move $10,$0 move $11,$0 move $12,$0 fl_c0: sb $10,20($8) sb $11,21($8) sb $12,22($8) addiu $8,$8,36 addi $9,$9,-1 bne $9,$0,fl_loop0 nop j fl_x fl_Remap_Sprites: lhu $10,WhichLineToFlush nop beq $10,$0,fl_Clear_Sprite_Line nop addi $10,$10,-1 j fl_Remap_Sprites_Row fl_Clear_Sprite_Line: li $11,0x88000000 li $12,11 fl_Clear_Sprite_Line_Loop: sw $11,0($8) addiu $8,$8,36 addi $12,$12,-1 bne $12,$0,fl_Clear_Sprite_Line_Loop nop j fl_Leave fl_Remap_Sprites_Row: li $3,36 li $12,11 multu $12,$3 nop nop mflo $12 sub $9,$8,$12 li $3,128 fl_Remap_Sprites_Row_Loop0: move $13,$8 move $14,$9 li $11,11 fl_Remap_Sprites_Row_Loop1: lw $15,0($14) lhu $24,16($14) lhu $25,18($14) sw $15,0($13) sh $24,16($13) sh $25,18($13) sb $3,20($13) sb $3,21($13) sb $3,22($13) addiu $14,$14,36 addiu $13,$13,36 addi $11,$11, -1 bne $11,$0,fl_Remap_Sprites_Row_Loop1 nop sub $8,$8,$12 sub $9,$9,$12 addi $10,$10,-1 bne $10,$0,fl_Remap_Sprites_Row_Loop0 nop j fl_Clear_Sprite_Line fl_Leave: sh $0,_line_flag fl_x: "); // jr ra } /* --------------------------------------------------------------------- ** Function: Game_Over_Clear_Field ** Description: Clear bottom line as long as there are no more lines. ** Count stones in each line and produce score out of it ** If all is done leave game (return 1) */ inline short Game_Over_Clear_Field(void) { typedef GsSPRITE spr; // .set reorder asm (" la $8,TetixxFieldSprites lh $3,WhichLineToFlushGameOver bgtz $3,gocf0 nop li $3,1 gocf0: addi $3,$3,-1 li $9,36 multu $3,$9 nop li $3,11 mflo $9 multu $3,$9 nop nop mflo $10 addu $8,$8,$10 lh $3,WhichLineToFlushCtrl nop bne $3,$0,gocf_Fade_Line nop li $10,255 li $3,11 li $12,0x88000000 gocf_Set_RGB: lw $13,0($8) nop beq $13,$12,gocf_Skip_RGB sb $10,20($8) sb $10,21($8) sb $10,22($8) gocf_Skip_RGB: addiu $8,$8,36 addi $3,$3,-1 bne $3,$0,gocf_Set_RGB nop lh $24,WhichLineToFlushGameOver nop bgtz $24,gocf1 nop li $24,1 gocf1: addi $24,$24,-1 la $8,TetixxField li $9,11+2 multu $9,$24 nop nop mflo $9 addu $8,$8,$9 addiu $8,$8,1 li $9,11 move $10,$0 gocf_Count_Line_Contens: lbu $11,0($8) nop beq $11,$0,gocf_clc0 nop addiu $10,$10,49 gocf_clc0: addiu $8,$8,1 addi $9,$9,-1 bne $9,$0,gocf_Count_Line_Contens nop sw $10,ScoreToAdd beq $10,$0,gocf_Flush_Next nop li $3,1 sh $3,WhichLineToFlushCtrl addiu $29, $29, -32 sw $31, 28($29) li $3, 96 sw $3, 24($29) sw $3, 20($29) sw $0, 16($29) li $7, 56 li $6, 8 move $5, $0 lhu $4, GameSfxVabID nop jal SsUtKeyOn nop lw $31, 28($29) move $2, $0 addiu $29, $29, 32 move $2, $0 j gofx gocf_Fade_Line: li $3,11 li $12,0x88000000 move $14,$8 gocf_Fade_Line_Loop: lw $13,0($8) nop beq $12,$13,gocf_Skip_Fade nop lbu $9,20($8) nop beq $9,$0,gocf_Line_Ready nop lbu $9,20($8) lbu $10,21($8) lbu $11,22($8) addi $9,$9,-64 addi $10,$10,-64 addi $11,$11,-64 bgtz $9,gocf_fl0 nop move $9,$0 move $10,$0 move $11,$0 gocf_fl0: sb $9,20($8) sb $10,21($8) sb $11,22($8) gocf_Skip_Fade: addiu $8, $8,36 addi $3,$3,-1 bne $3,$0,gocf_Fade_Line_Loop nop move $2,$0 j gofx gocf_Line_Ready: li $3,11 li $9,0x88000000 gocf_Set_Sprites_Off: sw $9,0($14) addiu $14,$14,36 addi $3,$3,-1 bne $3,$0,gocf_Set_Sprites_Off nop gocf_Flush_Next: lhu $8,WhichLineToFlushGameOver nop addi $8,$8,-1 beq $8,$0,gocf_Field_Ready nop sh $8,WhichLineToFlushGameOver sh $0,WhichLineToFlushCtrl move $2,$0 j gofx gocf_Field_Ready: sh $0,WhichLineToFlushCtrl li $2,1 gofx: "); // jr ra } /* --------------------------------------------------------------------- ** Function: Add_Up_Score ** Description: Adds the contents of ScoreToAdd to the CurrentGameHS.he_score ** ScoreToAdd is 0 do nothing */ inline void Add_Up_Score(void) { typedef HISCORE_ENTRY s; // .set reorder asm (" lw $8,ScoreToAdd nop bne $8, $0, aus_ADD nop j ausx aus_ADD: la $9,CurrentGameHS lw $10,0($9) nop addu $10,$10,$8 sw $10,0($9) sw $0,ScoreToAdd lw $11,CurrentHiscore nop bleu $10,$11,aus_No_HISCORE nop sw $10,CurrentHiscore lhu $3,HiscoreBeaten bne $3,$0,aus_No_HISCORE nop li $3,1 sh $3,HiscoreBeaten addiu $29,$29,-32 sw $31,28($29) li $3,127 sw $3,24($29) sw $3,20($29) sw $0,16($29) li $7,48 li $6,5 move $5,$0 lhu $4,GameSfxVabID nop jal SsUtKeyOn nop lw $31,28($29) move $2,$0 addiu $29,$29,32 aus_No_HISCORE: nop ausx: "); // jr ra } /* --------------------------------------------------------------------- ** Function: Convert_Score_To_AscII ** Description: Convert the score unsigned long integer to an AscII ** stirng */ inline void Score_To_AscII(void) { typedef HISCORE_ENTRY s; // .set reorder asm ("addiu $29, $29, -12 sw $31, 0($29) lw $5, CurrentHiscore la $4, GameHiScoreDec jal Long_To_AscII nop la $4, GameScoreDec la $8, CurrentGameHS sw $8, 4($29) lw $5, 0($8) nop jal Long_To_AscII nop la $4, GameLinesDec lw $8, 4($29) nop lw $5, 4($8) nop jal Long_To_AscII nop la $4, GameStonesDec lw $8, 4($29) nop lw $5, 8($8) nop jal Long_To_AscII nop lw $8,4($29) nop lw $14,12($8) nop la $15,GameTimeDec bne $14,$0,pt0 nop li $3,6 pt1: sb $0,0($15) nop addiu $15,$15,1 addi $3,$3,-1 bne $3,$0,pt1 nop j ptxx pt0: li $3,50 divu $14,$3 nop nop mflo $14 li $3,3600 divu $14,$3 nop nop mfhi $14 mflo $5 la $4,DecTemp sw $4,8($29) jal Long_To_AscII nop lw $8,8($29) nop lbu $9,8($8) lbu $10,9($8) sb $9,0($15) sb $10,1($15) li $3,60 divu $14,$3 nop nop mfhi $14 mflo $5 lw $4,8($29) nop jal Long_To_AscII nop lw $8,8($29) lbu $9,8($8) lbu $10,9($8) sb $9,2($15) sb $10,3($15) lw $4,8($29) move $5,$14 jal Long_To_AscII nop lw $8,8($29) nop lbu $9,8($8) lbu $10,9($8) sb $9,4($15) sb $10,5($15) ptxx: lw $31,0($29) addiu $29,$29,12 "); // jr ra } /* --------------------------------------------------------------------- ** Function: Long_To_AscII ** Description: Convert the unsgined long integer in a1 register. ** Put the AscII number in buffer (*buff = a0) */ inline void Long_To_AscII(unsigned char *strbuf, unsigned long n) { // .set reorder asm (" li $25,10 nop bne $5,$0,cstc nop cstzero: sb $0,0($4) nop addiu $4,$4,1 addi $25,$25,-1 bne $25,$0,cstzero nop j cstaxx cstc: la $8,poweroften csta0: lw $12,0($8) nop divu $5,$12 nop nop mfhi $5 mflo $12 sb $12,0($4) addiu $8,$8, 4 addiu $4,$4, 1 addi $25,$25, -1 nop bne $25,$0,csta0 nop cstaxx: nop "); // jr ra } /* --------------------------------------------------------------------- ** Function: Score_To_Sprite ** Description: Put the AscII number in sprite. */ inline void Score_To_Sprite(void) { typedef GsSPRITE spr; // .set reorder asm ("addiu $29, $29, -4 sw $31, 0($29) la $4,GameScoreDec la $5,GameScoreSprites nop jal Set_Monitor_Sprites nop la $4,GameHiScoreDec la $5,GameHiScoreSprites nop jal Set_Monitor_Sprites nop la $4,GameLinesDec la $5,GameLinesSprites nop jal Set_Monitor_Sprites nop la $4,GameStonesDec la $5,GameStonesSprites nop jal Set_Monitor_Sprites nop la $8,GameTimeDec la $9,GameTimeSprites la $10,NumbersVRAM_UV li $3,3 sts_Time: lbu $11,0($8) nop addu $12,$11,$11 addu $11,$12,$10 lbu $12,0($11) lbu $13,1($11) sb $12,14($9) sb $13,15($9) sw $0,0($9) addiu $9,$9,36 addiu $8,$8,1 lbu $11,0($8) nop addu $12,$11,$11 addu $11,$12,$10 lbu $12,0($11) lbu $13,1($11) sb $12,14($9) sb $13,15($9) sw $0,0($9) addiu $9,$9,36 addiu $8,$8,1 addi $3,$3,-1 nop beq $3,$0,sts_Leave nop sw $0,0($9) addiu $9,$9,36 j sts_Time sts_Leave: lw $31,0($29) nop addiu $29,$29,4 "); // jr ra } /* --------------------------------------------------------------------- ** Function: Set_Monitor_Sprites ** Description: Convert the AscII stining into sprites. */ inline void Set_Monitor_Sprites(unsigned char *str, GsSPRITE *gspr) { typedef GsSPRITE spr; // .set reorder asm (" move $8,$4 addiu $9,$4,9 addiu $14,$5,36*9 sms_KillZeros: lbu $10,0($8) nop bne $10,$0,sms_Set nop addiu $8,$8,1 nop bne $8,$9,sms_KillZeros nop sms_Set: la $10,NumbersVRAM_UV sms_Set_Loop: lbu $11,0($9) addu $11,$11,$11 addu $11,$11,$10 lbu $12,0($11) lbu $13,1($11) sw $0,0($5) sb $12,14($5) sb $13,15($5) addiu $5,$5,36 nop beq $8,$9,sms_Set_Rest_Off nop addiu $9, $9, -1 j sms_Set_Loop sms_Set_Rest_Off: li $15, 0x88000000 beq $5,$14,sms_Leave nop sms_Set_Rest_Off_Loop: sw $15,0($5) nop addiu $5,$5,36 nop bne $5,$14,sms_Set_Rest_Off_Loop nop sms_Leave: nop "); // jr ra } /* --------------------------------------------------------------------- ** Function: Flash_Score ** Description: If hiscore is beaten flash score */ inline void Flash_Score(void) { typedef GsSPRITE spr; // .set reorder asm (" lhu $8,HiscoreBeaten nop bne $8,$0,fs_yeah nop j fsxx fs_yeah: lhu $8,HiscoreBeatenFlag nop bne $8,$0,fs_Flash nop fs_Set_Score_R: la $8,GameScoreSprites li $9,0x88000000 li $10,9 li $11,255 fs_Set_Score_R_loop: lw $12,0($8) nop beq $9,$12,fs_No_Set nop sb $11,20($8) sb $11,21($8) sb $11,22($8) fs_No_Set: addiu $8,$8,36 addi $10,$10,-1 bne $10,$0,fs_Set_Score_R_loop nop li $3,1 sh $3,HiscoreBeatenFlag j fsxx fs_Flash: la $8,GameScoreSprites li $9,0x88000000 li $10,9 fs_Flash_l0: lw $12,0($8) nop beq $9,$12,fs_no_flash nop lbu $13,20($8) nop sltiu $3,$13,128 bne $3,$0,fs_Reflash nop addiu $13,$13,-8 sb $13,20($8) sb $13,21($8) sb $13,22($8) fs_no_flash: addiu $8,$8,36 addi $10,$10,-1 bne $10,$0,fs_Flash_l0 nop j fsxx fs_Reflash: sh $0,HiscoreBeatenFlag nop fsxx: "); // jr ra } /* --------------------------------------------------------------------- ** Function: Game_Over_Score ** Description: Give bound for Lines/Stones/Time */ void Game_Over_Score(void) { unsigned long base, val,subval, score; short delay,i; TempScore_Lines = CurrentGameHS.he_lines; TempScore_Stones = CurrentGameHS.he_stones; TempScore_Time = CurrentGameHS.he_playtime; // Score for Lines base = 10; score = GAME_OVER_SCORE_LINE; delay = 0; while (CurrentGameHS.he_lines) { val = (CurrentGameHS.he_lines % base); subval = base / 10; val = (val / subval); for(i=0; i