/* --------------------------------------------------------------------- ** Project: Tetixx (a Tetris clone) ** File: thegame.c ** StartDate: 20.03.1999 ** Autor: Robert Jurziga */ #include #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); asm short Apply_Stone(void); asm short Apply_Stone_Left(void); asm short Apply_Stone_Right(void); asm short Apply_Stone_Flip(void); asm 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); asm void Clear_Tetixx_Field(void); asm void Reset_Tetixx_Field_Sprites(void); asm void Reset_Tetixx_Monitor_Sprites(void); asm void Draw_Stone_Shape_In_Field(void); asm short Check_Lines(void); asm void Flush_Line(void); asm short Game_Over_Clear_Field(void); asm void Add_Up_Score(void); asm void Score_To_AscII(void); asm void Long_To_AscII(unsigned char *strbuf, unsigned long n); asm void Score_To_Sprite(void); asm void Set_Monitor_Sprites(unsigned char *str, GsSPRITE *gspr); asm void Flash_Score(void); void Game_Over_Score(void); // --------------------------------------------------------------------- // V A R I A B L E S // --------------------------------------------------------------------- int _ActiBuf; ulong _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}; struct 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 }; struct 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 }; struct 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 }; struct 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 }; struct 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 }; struct 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 }; struct 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 }; struct 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 }; struct 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 }; struct 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 }; struct 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 }; struct 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 ** */ asm void Clear_Tetixx_Field(void) { .set reorder la t0, TetixxField li t1, 1 li t2, STONES_ROWS ctf_loop: li t3, STONES_IN_ROW sb t1, 0(t0) // wall at left addiu t0, t0, 1 ctf_loop1: sb $0,0(t0) addiu t0, t0, 1 addi t3, t3, -1 bne t3, $0, ctf_loop1 sb t1,0(t0) // wall at right addiu t0, t0, 1 addi t2, t2, -1 bne t2, $0, ctf_loop // ROWS times li t2, STONES_IN_ROW+2 ctf_loop2: // draw the bottom sb t1, 0(t0) addiu t0, t0, 1 addi t2, t2, -1 bne t2, $0, ctf_loop2 jr ra } /* --------------------------------------------------------------------- ** Function: Reset_Tetixx_Field_Sprites ** Description: */ asm void Reset_Tetixx_Field_Sprites(void) { typedef GsSPRITE spr; .set reorder la t0, TetixxFieldSprites li t1, 0x88000000 li t2, TETIXX_FIELD_YOFF li t3, STONES_ROWS li t6, 128 rtfs_loop0: li t4, STONES_IN_ROW li t5, TETIXX_FIELD_XOFF rtfs_loop1: sw t1, spr.attribute(t0) sh t2, spr.y(t0) sh t5, spr.x(t0) sb t6, spr.r(t0) sb t6, spr.g(t0) sb t6, spr.b(t0) addiu t5, t5, STONE_WIDTH addi t4, t4, -1 addiu t0, t0, sizeof(GsSPRITE) bne t4, $0, rtfs_loop1 addiu t2, t2, STONE_HEIGHT addi t3, t3, -1 bne t3, $0, rtfs_loop0 jr ra } /* --------------------------------------------------------------------- ** Function: Reset_Tetixx_Monitor_Sprites ** Description: */ asm void Reset_Tetixx_Monitor_Sprites(void) { typedef GsSPRITE spr; .set reorder la t0, GameTimeSprites la t1, NumbersVRAM_UV lbu t4, 0(t1) // get U lbu t5, 1(t1) // get V for 0 lbu t6, 20(t1) // get U lbu t7, 21(t1) // get V for : li at, 3 rtms_Reset_Time_Loop: sw $0, spr.attribute(t0) // 00 sb t4, spr.u(t0) sb t5, spr.v(t0) addiu t0, t0, sizeof(GsSPRITE) sw $0, spr.attribute(t0) sb t4, spr.u(t0) sb t5, spr.v(t0) addiu t0, t0, sizeof(GsSPRITE) addi at, at, -1 // -1 nop beq at, $0, rtms_Reset_Score // if zero reset Socre sw $0, spr.attribute(t0) // set : sb t6, spr.u(t0) sb t7, spr.v(t0) addiu t0, t0, sizeof(GsSPRITE) b rtms_Reset_Time_Loop rtms_Reset_Score: la t0, GameScoreSprites li at, 8 li t2, 0x88000000 li t3, 128 // brightness sw $0, spr.attribute(t0) // set the 1st sprite to 0 sb t4, spr.u(t0) sb t5, spr.v(t0) sb t3, spr.r(t0) sb t3, spr.g(t0) sb t3, spr.b(t0) addiu t0, t0, sizeof(GsSPRITE) rtms_Reset_Score_Loop: sw t2, spr.attribute(t0) // set sprite attribute sb t3, spr.r(t0) sb t3, spr.g(t0) sb t3, spr.b(t0) addi at, at, -1 addiu t0, t0, sizeof(GsSPRITE) bne at, $0, rtms_Reset_Score_Loop la t0, GameHiScoreSprites li at, 8 sw $0, spr.attribute(t0) sb t4, spr.u(t0) sb t5, spr.v(t0) addiu t0, t0, sizeof(GsSPRITE) rtms_Reset_Hiscore_Loop: sw t2, spr.attribute(t0) addi at, at, -1 addiu t0, t0, sizeof(GsSPRITE) bne at, $0, rtms_Reset_Hiscore_Loop la t0, GameLinesSprites li at, 8 sw $0, spr.attribute(t0) sb t4, spr.u(t0) sb t5, spr.v(t0) addiu t0, t0, sizeof(GsSPRITE) rtms_Reset_Lines_Loop: sw t2, spr.attribute(t0) addi at, at, -1 addiu t0, t0, sizeof(GsSPRITE) bne at, $0, rtms_Reset_Lines_Loop la t0, GameStonesSprites li at, 8 sw $0, spr.attribute(t0) sb t4, spr.u(t0) sb t5, spr.v(t0) addiu t0, t0, sizeof(GsSPRITE) rtms_Reset_Stones_Loop: sw t2, spr.attribute(t0) addi at, at, -1 addiu t0, t0, sizeof(GsSPRITE) bne at, $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. */ asm short Apply_Stone(void) { .set reorder lw t0, CurrStoneShape // its a pointer la t1, TetixxField sb $0, 0(t0) // allway first shape addiu t0, t0, 2 // skip (step / steps) lh t2, stone_mxoff addu t1, t2, t1 // get x position in field addiu t1, t1, 1 // skip left wall li t5, 4 as_loop0: li t6, 4 move t2, t1 // get copy as_loop1: lbu t3, 0(t0) // get shape byte lbu t4, 0(t2) // get field byte beq t3, $0, as_c0 bne t4, $0, as_game_over as_c0: addiu t0, t0, 1 // next shape byte addiu t2, t2, 1 // next field byte addi t6, t6, -1 bne t6, $0, as_loop1 addiu t1, t1, STONES_IN_ROW+2 // pointer to next row in field addi t5, t5, -1 bne t5, $0, as_loop0 li v0, 0 // playing allowed jr ra as_game_over: // no room for new stone li v0, 1 jr ra } /* --------------------------------------------------------------------- ** Function: Apply_Stone_Left ** Description: Check if moving to left is allowed. ** If move is allowed return 1 ** If not return 0 */ asm short Apply_Stone_Left(void) { .set reorder lw t0, CurrStoneShape // its a pointer la t1, TetixxField lbu t2, 0(t0) // get step (which shape) addiu t0, t0, 2 // skip (step / steps) sll t2, t2, 4 // * 16 addu t0, t0, t2 // point at right shape lh t2, stone_mxoff lhu t3, stone_myoff addi t2, t2, 1 // skip wall li at, STONES_IN_ROW+2 multu at, t3 // row*stones_in_row+2 mflo t3 addu t1, t1, t3 // get row in field addu t1, t1, t2 // + xoffset li t3, 4 asl_loop0: li t4, 4 move t5, t1 // make a copy move t6, t0 // make a copy too asl_loop1: lbu t8, 0(t6) // get byte in shape beq t8, $0, asl_c0 // if NULL next lbu t9, -1(t5) // get prevoise byte (where to move) bne t9, $0, asl_not_allowed b asl_n0 // do next row asl_c0: addiu t5, t5, 1 addiu t6, t6, 1 addi t4, t4, -1 bne t4, $0, asl_loop1 asl_n0: addiu t0, t0, 4 // next row in shape addiu t1, t1, STONES_IN_ROW+2 // next row in field addi t3, t3, -1 bne t3, $0, asl_loop0 li v0, 1 // signal move left is allowd jr ra asl_not_allowed: move v0, $0 jr ra } /* --------------------------------------------------------------------- ** Function: Apply_Stone_Right ** Description: Check if moving to right is allowed. ** If move is allowed return 1 ** If not return 0 */ asm short Apply_Stone_Right(void) { .set reorder lw t0, CurrStoneShape // its a pointer la t1, TetixxField lbu t2, 0(t0) // get step (which shape) addiu t0, t0, 2 // skip (step / steps) sll t2, t2, 4 // * 16 addu t0, t0, t2 // point at right shape lh t2, stone_mxoff lhu t3, stone_myoff addi t2, t2, 1 // skip wall li at, STONES_IN_ROW+2 multu at, t3 // row*stones_in_row+2 mflo t3 addu t1, t1, t3 // get row in field addu t1, t1, t2 // + xoffset addiu t0, t0, 3 // go on last byte in shape addiu t1, t1, 3 // ditto for field li t3, 4 asr_loop0: li t4, 4 move t5, t1 move t6, t0 asr_loop1: lbu t8, 0(t6) // get byte in shape beq t8, $0, asr_c0 lbu t9, 1(t5) // get next positon in field bne t9, $0, asr_not_allowed b asr_n0 asr_c0: addi t5, t5, -1 addi t6, t6, -1 addi t4, t4, -1 bne t4, $0, asr_loop1 asr_n0: addiu t0, t0, 4 addiu t1, t1, STONES_IN_ROW+2 addi t3, t3, -1 bne t3, $0, asr_loop0 li v0, 1 jr ra asr_not_allowed: move v0, $0 jr ra } /* --------------------------------------------------------------------- ** Function: Apply_Stone_Flip ** Description: Check if stone can be flipped. */ asm short Apply_Stone_Flip(void) { .set reorder lw t0, CurrStoneShape lbu t8, 0(t0) lbu t9, 1(t0) addiu t8, t8, 1 bne t8, t9, asf_c0 move t8, $0 asf_c0: addiu t1, t0, 2 // skip (step/steps) sll t2, t8, 4 // * 16 addu t1, t1, t2 la t2, TetixxField // calculate offset in field lh t3, stone_mxoff lhu t4, stone_myoff addi t3, t3, 1 // skip wall li at, STONES_IN_ROW+2 multu at, t4 // row*stones_in_row+2 mflo t4 addu t2, t2, t4 // get row in field addu t2, t2, t3 // + xoffset li t3, 4 asf_loop0: li t4, 4 move t5, t2 asf_loop1: lbu t6, 0(t1) lbu t7, 0(t5) beq t6, $0, asf_n0 bne t7, $0, asf_no_flip asf_n0: addiu t1, t1, 1 addiu t5, t5, 1 addi t4, t4, -1 bne t4, $0, asf_loop1 addiu t2, t2, STONES_IN_ROW+2 addi t3, t3, -1 bne t3, $0, asf_loop0 sb t8, 0(t0) li v0, 1 jr ra asf_no_flip: move v0, $0 jr ra } /* --------------------------------------------------------------------- ** Function: Apply_Stone_Down ** Description: Check the stone bottom form bottom to top */ asm short Apply_Stone_Down(void) { .set reorder lw t0, CurrStoneShape lbu t1, 0(t0) // point at current shape sll t1, t1, 4 addiu t1, t1, 2 addu t0, t0, t1 la t1, TetixxField lh t2, stone_mxoff lhu t3, stone_myoff addi t2, t2, 1 // skip wall addiu t3, t3, 3 // +hight of stone -1 li at, STONES_IN_ROW+2 multu at, t3 // row*stones_in_row+2 mflo t3 addu t1, t1, t3 // get row in field addu t1, t1, t2 // + xoffset addiu t0, t0, 12 // + stone width*(stoneheight-1) li t2, 4 asd_loop0: li t3, 4 move t5, t0 move t6, t1 asd_loop1: lbu t7, 0(t5) // get byte in shape beq t7, $0, asd_c0 lbu t8, STONES_IN_ROW+2(t6) bne t8, $0, asd_put_stone b asd_n0 asd_c0: addi t5, t5, -4 addi t6, t6, -(STONES_IN_ROW+2) addi t3, t3, -1 bne t3, $0, asd_loop1 asd_n0: addiu t0, t0, 1 addiu t1, t1, 1 addi t2, t2, -1 bne t2, $0, asd_loop0 li v0,1 jr ra asd_put_stone: move v0, $0 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. */ asm void Draw_Stone_Shape_In_Field(void) { typedef GsSPRITE spr; .set reorder lw t0, CurrStoneShape la t1, TetixxField la t2, TetixxFieldSprites lbu t3, 0(t0) // point at right shape sll t3, t3, 4 addiu t0, t0, 2 addu t0, t0, t3 lh t3, stone_mxoff // get the location in Tetixx Field lhu t4, stone_myoff addi t3, t3, 1 // skip wall li at, STONES_IN_ROW+2 multu at, t4 // row*stones_in_row+2 mflo t5 addu t1, t1, t5 // get row in field addu t1, t1, t3 // + xoffset li at, sizeof(GsSPRITE) // mxoff * sizeof(GsSPRITE) addi t3, t3, -1 // no wall -1 multu at, t3 li t5, STONES_IN_ROW mflo t3 // get resutl addu t2, t2, t3 // spr+=xoff multu t5, at // STONES_IN_ROW*sizeof(GsSPRITE) nop nop mflo t3 multu t4, t3 nop nop mflo t4 addu t2, t2, t4 // addup lhu v0, currclutx lhu v1, currcluty li t5,4 dssif_loop0: li t6, 4 move t7, t1 move t8, t2 dssif_loop1: lbu t9, 0(t0) beq t9, $0, dssif_c0 // skip 0x0 sb t9, 0(t7) sw $0, spr.attribute(t8) // clear ON/OFF Flag sh v0, spr.cx(t8) sh v1, spr.cy(t8) dssif_c0: addiu t0, t0, 1 addiu t7, t7, 1 addiu t8, t8, sizeof(GsSPRITE) addi t6, t6, -1 bne t6, $0, dssif_loop1 addiu t1, t1, STONES_IN_ROW+2 addu t2, t2, t3 // STONES_IN_ROW *sizeof(GsSPRITE) addi t5, t5, -1 bne t5, $0, dssif_loop0 jr ra } /* --------------------------------------------------------------------- ** Function: Check_Lines ** Description: Test if lines are completed. */ asm short Check_Lines(void) { typedef GsSPRITE spr; .set reorder la t0, TetixxField li at, STONES_IN_ROW move t9, $0 // line count li t1, STONES_ROWS cl_loop0: li t2, STONES_IN_ROW addiu t0, t0, 1 // skip wall move t3, $0 // clear counter cl_loop1: lbu t4, 0(t0) addu t3, t3, t4 addiu t0, t0, 1 addi t2, t2, -1 bne t2, $0, cl_loop1 nop beq t3, at, cl_Line_Found // Field Line sum == STONES_IN_ROW nop addiu t9, t9, 1 // add line count addiu t0, t0, 1 // skip right wall addi t1, t1, -1 bne t1, $0, cl_loop0 // no lines found li at, 34 sh at, _flush_line_note sw $0, LinesScore sh $0, WhichLineToFlush move v0, $0 jr ra cl_Line_Found: li at, sizeof(GsSPRITE) li t1, STONES_IN_ROW multu at, t1 nop nop mflo t1 multu t9, t1 // calculate the sprite line nop nop mflo t4 la t2, TetixxFieldSprites addu t2, t2, t4 // t2=ptr to 1st sprite of flushing line sw t2, SpriteLineToFlush sh t9, WhichLineToFlush li t3, 255 li t5, 0x60000000 // set semi transparency li t4, STONES_IN_ROW cl_SetSprite_RGB: // set current line RGB to highest brightness sw t5, spr.attribute(t2) // and semitransparncy sb t3, spr.r(t2) // sb t3, spr.g(t2) sb t3, spr.b(t2) addiu t2, t2, sizeof(GsSPRITE) addi t4, t4, -1 bne t4, $0, cl_SetSprite_RGB addi t0, t0, -(STONES_IN_ROW+1) // rewind checked line + wall beq t9, $0, cl_Clear_Line // if is NULL line clear only line nop addi t9, t9, -1 // whichline -- b cl_Remap_Field // else Remape field cl_Clear_Line: li t1, STONES_IN_ROW cl_Clear_Line_Loop: sb $0, 1(t0) nop addiu t0, t0, 1 addi t1, t1, -1 nop bne t1, $0, cl_Clear_Line_Loop b cl_Leave cl_Remap_Field: // remap the field form line-1 to top addi t1, t0, -(STONES_IN_ROW+2) cl_Remap_Field_Loop: lbu t2, 0(t1) lbu t3, 1(t1) lbu t4, 2(t1) lbu t5, 3(t1) lbu t6, 4(t1) lbu t7, 5(t1) lbu t8, 6(t1) sb t2, 0(t0) sb t3, 1(t0) sb t4, 2(t0) sb t5, 3(t0) sb t6, 4(t0) sb t7, 5(t0) sb t8, 6(t0) lbu t2, 7(t1) lbu t3, 8(t1) lbu t4, 9(t1) lbu t5, 10(t1) lbu t6, 11(t1) lbu t7, 12(t1) sb t2, 7(t0) sb t3, 8(t0) sb t4, 9(t0) sb t5, 10(t0) sb t6, 11(t0) sb t7, 12(t0) addi t9, t9, -1 addiu t0, t0, -(STONES_IN_ROW+2) addiu t1, t1, -(STONES_IN_ROW+2) slti at, t9, 0 beq at, $0, cl_Remap_Field_Loop nop b cl_Clear_Line cl_Leave: lhu at, _flush_line_note addiu at, at, 2 sh at, _flush_line_note lw at, LinesScore lw t0, ScoreToAdd addu t0, t0, at sw t0, ScoreToAdd addiu at, at, SCORE_FLUSH_LINE sw at, LinesScore li v0, 1 jr ra } /* --------------------------------------------------------------------- ** Function: Flush_Line ** Description: Fade down the line sprite RGB fast. Then Remap sprites */ asm void Flush_Line(void) { typedef GsSPRITE spr; .set reorder lw t0, SpriteLineToFlush li t1, STONES_IN_ROW lb t2, spr.r(t0) beq t2, $0, fl_Remap_Sprites nop fl_loop0: lbu t2, spr.r(t0) lbu t3, spr.g(t0) lbu t4, spr.b(t0) addi t2, t2, -24 addi t3, t3, -24 addi t4, t4, -24 bgtz t2, fl_c0 move t2, $0 move t3, $0 move t4, $0 fl_c0: sb t2, spr.r(t0) sb t3, spr.g(t0) sb t4, spr.b(t0) addiu t0, t0, sizeof(GsSPRITE) addi t1, t1, -1 bne t1, $0, fl_loop0 nop nop jr ra fl_Remap_Sprites: lhu t2, WhichLineToFlush beq t2, $0, fl_Clear_Sprite_Line addi t2, t2, -1 b fl_Remap_Sprites_Row fl_Clear_Sprite_Line: li t3, 0x88000000 li t4, STONES_IN_ROW fl_Clear_Sprite_Line_Loop: sw t3, spr.attribute(t0) addiu t0, t0, sizeof(GsSPRITE) addi t4, t4, -1 bne t4, $0, fl_Clear_Sprite_Line_Loop b fl_Leave fl_Remap_Sprites_Row: li at, sizeof(GsSPRITE) li t4, STONES_IN_ROW multu t4, at nop nop mflo t4 sub t1, t0, t4 li at, 128 fl_Remap_Sprites_Row_Loop0: move t5, t0 move t6, t1 li t3, STONES_IN_ROW fl_Remap_Sprites_Row_Loop1: lw t7, spr.attribute(t6) lhu t8, spr.cx(t6) lhu t9, spr.cy(t6) sw t7, spr.attribute(t5) sh t8, spr.cx(t5) sh t9, spr.cy(t5) sb at, spr.r(t5) sb at, spr.g(t5) sb at, spr.b(t5) addiu t6, t6, sizeof(GsSPRITE) addiu t5, t5, sizeof(GsSPRITE) addi t3, t3, -1 bne t3, $0, fl_Remap_Sprites_Row_Loop1 sub t0, t0, t4 sub t1, t1, t4 addi t2, t2, -1 bne t2, $0, fl_Remap_Sprites_Row_Loop0 nop b fl_Clear_Sprite_Line fl_Leave: sh $0, _line_flag 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) */ asm short Game_Over_Clear_Field(void) { typedef GsSPRITE spr; .set reorder la t0, TetixxFieldSprites lh at, WhichLineToFlushGameOver bgtz at, gocf0 li at, 1 gocf0: addi at, at, -1 li t1, sizeof(GsSPRITE) // line * sizeof(GsSPRITE) multu at, t1 nop li at, STONES_IN_ROW mflo t1 multu at, t1 // * STONES IN ROW nop nop mflo t2 addu t0, t0, t2 // point at first Sprite Line lh at, WhichLineToFlushCtrl // if == NULL bne at, $0, gocf_Fade_Line // t0 = TetixxField Sprites PTR li t2, 255 // max brightness li at, STONES_IN_ROW // counter li t4, 0x88000000 // off flag gocf_Set_RGB: lw t5, spr.attribute(t0) // get attribute nop beq t5, t4, gocf_Skip_RGB // if OFF no set sb t2, spr.r(t0) // set max brightness r sb t2, spr.g(t0) // g sb t2, spr.b(t0) // b gocf_Skip_RGB: addiu t0, t0, sizeof(GsSPRITE) // next sprite addi at, at, -1 // counter-- bne at, $0, gocf_Set_RGB // set loop lh t8, WhichLineToFlushGameOver bgtz t8, gocf1 li t8, 1 gocf1: addi t8, t8, -1 la t0, TetixxField li t1, STONES_IN_ROW+2 // +2 (walls) multu t1, t8 // line to flush * STONES_IN_ROW + nop nop mflo t1 addu t0, t0, t1 // pointer to 1st line byte addiu t0, t0, 1 // skip wall li t1, STONES_IN_ROW // counter move t2, $0 // clear score sum gocf_Count_Line_Contens: lbu t3, 0(t0) // get byte nop beq t3, $0, gocf_clc0 // if not no score nop addiu t2, t2, SCORE_ZAP_LINE // for each stone part in row give points gocf_clc0: addiu t0, t0, 1 // next stone addi t1, t1, -1 // counter-- bne t1, $0, gocf_Count_Line_Contens // loop it sw t2, ScoreToAdd // stonre score beq t2, $0, gocf_Flush_Next // if line was empty do next li at, 1 sh at, WhichLineToFlushCtrl // signal to fade down line addiu sp, sp, -32 // play zap sound sw ra, 28(sp) li at, 96 sw at, 24(sp) sw at, 20(sp) sw $0, 16(sp) li a3, 56 li a2, GSFX_ZAP_LINE move a1, $0 lhu a0, GameSfxVabID nop jal SsUtKeyOn nop lw ra, 28(sp) move v0, $0 addiu sp, sp, 32 move v0, $0 // signal line not ready jr ra gocf_Fade_Line: li at, STONES_IN_ROW // t0 = *sprites li t4, 0x88000000 // OFF flag move t6, t0 // save ptr gocf_Fade_Line_Loop: lw t5, spr.attribute(t0) // get attrib nop beq t4, t5, gocf_Skip_Fade // if OFF don't fade lbu t1, spr.r(t0) // get spr.r nop // if NULL fade DONE beq t1, $0, gocf_Line_Ready nop lbu t1, spr.r(t0) lbu t2, spr.g(t0) // get g lbu t3, spr.b(t0) // get b addi t1, t1, -64 // brightness - 64 addi t2, t2, -64 addi t3, t3, -64 bgtz t1, gocf_fl0 // if <= 0 move t1, $0 // set brightness to ZERO move t2, $0 move t3, $0 gocf_fl0: sb t1, spr.r(t0) // set brightness sb t2, spr.g(t0) // g sb t3, spr.b(t0) // b gocf_Skip_Fade: addiu t0, t0, sizeof(GsSPRITE) // next sprite addi at, at, -1 // counter-- bne at, $0, gocf_Fade_Line_Loop // looper move v0, $0 // signal not ready jr ra gocf_Line_Ready: // t6 = *sprites li at, STONES_IN_ROW li t1, 0x88000000 // OFF gocf_Set_Sprites_Off: sw t1, spr.attribute(t6) // set whole sprite line addiu t6, t6, sizeof(GsSPRITE) // to off addi at, at, -1 bne at, $0, gocf_Set_Sprites_Off gocf_Flush_Next: lhu t0, WhichLineToFlushGameOver // get line above addi t0, t0, -1 beq t0, $0, gocf_Field_Ready // if -1 field is ready sh t0, WhichLineToFlushGameOver // update line number sh $0, WhichLineToFlushCtrl // clear Cntrl move v0, $0 // signal field not ready jr ra gocf_Field_Ready: sh $0, WhichLineToFlushCtrl // clear ctrl li v0, 1 // signal field ready jr ra } /* --------------------------------------------------------------------- ** Function: Add_Up_Score ** Description: Adds the contents of ScoreToAdd to the CurrentGameHS.he_score ** ScoreToAdd is 0 do nothing */ asm void Add_Up_Score(void) { typedef HISCORE_ENTRY s; .set reorder lw t0, ScoreToAdd bne t0, $0, aus_ADD nop jr ra aus_ADD: la t1, CurrentGameHS lw t2, s.he_score(t1) nop addu t2, t2, t0 sw t2, s.he_score(t1) sw $0, ScoreToAdd lw t3, CurrentHiscore bleu t2, t3, aus_No_HISCORE sw t2, CurrentHiscore // stone new hiscore lhu at, HiscoreBeaten bne at, $0, aus_No_HISCORE li at, 1 // sound is play on time sh at, HiscoreBeaten addiu sp, sp, -32 sw ra, 28(sp) li at, 127 sw at, 24(sp) sw at, 20(sp) sw $0, 16(sp) li a3, 48 li a2, GSFX_NEW_HISCORE move a1, $0 lhu a0, GameSfxVabID jal SsUtKeyOn nop lw ra, 28(sp) move v0, $0 addiu sp, sp, 32 aus_No_HISCORE: nop jr ra } /* --------------------------------------------------------------------- ** Function: Convert_Score_To_AscII ** Description: Convert the score unsigned long integer to an AscII ** stirng */ asm void Score_To_AscII(void) { typedef HISCORE_ENTRY s; .set reorder addiu sp, sp, -12 sw ra, 0(sp) lw a1, CurrentHiscore la a0, GameHiScoreDec jal Long_To_AscII nop la a0, GameScoreDec la t0, CurrentGameHS sw t0, 4(sp) lw a1, s.he_score(t0) jal Long_To_AscII nop la a0, GameLinesDec lw t0, 4(sp) lw a1, s.he_lines(t0) jal Long_To_AscII nop la a0, GameStonesDec lw t0, 4(sp) lw a1, s.he_stones(t0) jal Long_To_AscII nop lw t0, 4(sp) lw t6, s.he_playtime(t0) la t7, GameTimeDec bne t6, $0, pt0 li at, 6 pt1: sb $0, 0(t7) nop addiu t7, t7, 1 addi at, at, -1 bne at, $0, pt1 lw ra, 0(sp) nop addiu sp, sp, 12 jr ra pt0: li at, 50 divu t6, at nop nop mflo t6 // get seconds li at, 3600 divu t6, at nop nop mfhi t6 mflo a1 la a0, DecTemp sw a0, 8(sp) jal Long_To_AscII nop lw t0, 8(sp) lbu t1, 8(t0) lbu t2, 9(t0) sb t1, 0(t7) sb t2, 1(t7) li at, 60 divu t6, at nop nop mfhi t6 mflo a1 lw a0, 8(sp) nop jal Long_To_AscII nop lw t0, 8(sp) lbu t1, 8(t0) lbu t2, 9(t0) sb t1, 2(t7) sb t2, 3(t7) lw a0, 8(sp) move a1, t6 jal Long_To_AscII nop lw t0, 8(sp) lbu t1, 8(t0) lbu t2, 9(t0) sb t1, 4(t7) sb t2, 5(t7) lw ra, 0(sp) addiu sp, sp, 12 jr ra } /* --------------------------------------------------------------------- ** Function: Long_To_AscII ** Description: Convert the unsgined long integer in a1 register. ** Put the AscII number in buffer (*buff = a0) */ asm void Long_To_AscII(unsigned char *strbuf, unsigned long n) { .set reorder li t9, 10 nop bne a1, $0, cstc cstzero: sb $0, 0(a0) nop addiu a0, a0, 1 addi t9, t9, -1 bne t9, $0, cstzero nop jr ra cstc: la t0, poweroften csta0: lw t4, 0(t0) nop divu a1, t4 nop nop mfhi a1 mflo t4 sb t4, 0(a0) addiu t0, t0, 4 addiu a0, a0, 1 addi t9, t9, -1 nop bne t9, $0, csta0 nop jr ra } /* --------------------------------------------------------------------- ** Function: Score_To_Sprite ** Description: Put the AscII number in sprite. */ asm void Score_To_Sprite(void) { typedef GsSPRITE spr; .set reorder addiu sp, sp, -4 sw ra, 0(sp) la a0, GameScoreDec la a1, GameScoreSprites nop jal Set_Monitor_Sprites nop la a0, GameHiScoreDec la a1, GameHiScoreSprites nop jal Set_Monitor_Sprites nop la a0, GameLinesDec la a1, GameLinesSprites nop jal Set_Monitor_Sprites nop la a0, GameStonesDec la a1, GameStonesSprites nop jal Set_Monitor_Sprites nop la t0, GameTimeDec la t1, GameTimeSprites la t2, NumbersVRAM_UV li at, 3 sts_Time: lbu t3, 0(t0) addu t4, t3, t3 addu t3, t4, t2 lbu t4, 0(t3) lbu t5, 1(t3) sb t4, spr.u(t1) sb t5, spr.v(t1) sw $0, spr.attribute(t1) addiu t1, t1, sizeof(GsSPRITE) addiu t0, t0, 1 lbu t3, 0(t0) addu t4, t3, t3 addu t3, t4, t2 lbu t4, 0(t3) lbu t5, 1(t3) sb t4, spr.u(t1) sb t5, spr.v(t1) sw $0, spr.attribute(t1) addiu t1, t1, sizeof(GsSPRITE) addiu t0, t0, 1 addi at, at, -1 nop beq at, $0, sts_Leave sw $0, spr.attribute(t1) addiu t1, t1, sizeof(GsSPRITE) // skip : b sts_Time sts_Leave: lw ra, 0(sp) nop addiu sp, sp, 4 jr ra } /* --------------------------------------------------------------------- ** Function: Set_Monitor_Sprites ** Description: Convert the AscII stining into sprites. */ asm void Set_Monitor_Sprites(unsigned char *str, GsSPRITE *gspr) { typedef GsSPRITE spr; .set reorder move t0, a0 addiu t1, a0, 9 addiu t6, a1, (sizeof(GsSPRITE) * 9) sms_KillZeros: lbu t2, 0(t0) bne t2, $0, sms_Set nop addiu t0, t0, 1 nop bne t0, t1, sms_KillZeros sms_Set: la t2, NumbersVRAM_UV sms_Set_Loop: lbu t3, 0(t1) addu t3, t3, t3 addu t3, t3, t2 lbu t4, 0(t3) lbu t5, 1(t3) sw $0, spr.attribute(a1) sb t4, spr.u(a1) sb t5, spr.v(a1) addiu a1, a1, sizeof(GsSPRITE) nop beq t0, t1, sms_Set_Rest_Off nop addiu t1, t1, -1 b sms_Set_Loop sms_Set_Rest_Off: li t7, 0x88000000 beq a1, t6, sms_Leave nop sms_Set_Rest_Off_Loop: sw t7, spr.attribute(a1) nop addiu a1, a1, sizeof(GsSPRITE) nop bne a1, t6, sms_Set_Rest_Off_Loop sms_Leave: nop jr ra } /* --------------------------------------------------------------------- ** Function: Flash_Score ** Description: If hiscore is beaten flash score */ asm void Flash_Score(void) { typedef GsSPRITE spr; .set reorder lhu t0, HiscoreBeaten nop bne t0, $0, fs_yeah nop jr ra fs_yeah: lhu t0, HiscoreBeatenFlag nop bne t0, $0, fs_Flash nop fs_Set_Score_R: la t0, GameScoreSprites li t1, 0x88000000 li t2, 9 li t3, 255 fs_Set_Score_R_loop: lw t4, spr.attribute(t0) nop beq t1, t4, fs_No_Set nop sb t3, spr.r(t0) sb t3, spr.g(t0) sb t3, spr.b(t0) fs_No_Set: addiu t0, t0, sizeof(GsSPRITE) addi t2, t2, -1 bne t2, $0, fs_Set_Score_R_loop li at, 1 sh at, HiscoreBeatenFlag jr ra fs_Flash: la t0, GameScoreSprites li t1, 0x88000000 li t2, 9 fs_Flash_l0: lw t4, spr.attribute(t0) nop beq t1, t4, fs_no_flash lbu t5, spr.r(t0) sltiu at, t5, 128 bne at, $0, fs_Reflash addiu t5, t5, -8 sb t5, spr.r(t0) sb t5, spr.g(t0) sb t5, spr.b(t0) fs_no_flash: addiu t0, t0, sizeof(GsSPRITE) addi t2, t2, -1 bne t2, $0, fs_Flash_l0 nop jr ra fs_Reflash: sh $0, HiscoreBeatenFlag nop 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