paulo@0: /* GBA frontend for LOCKJAW, an implementation of the Soviet Mind Game paulo@0: paulo@0: Copyright (C) 2006-2007 Damian Yerrick paulo@0: paulo@0: This work is free software; you can redistribute it and/or modify paulo@0: it under the terms of the GNU General Public License as published by paulo@0: the Free Software Foundation; either version 2 of the License, or paulo@0: (at your option) any later version. paulo@0: paulo@0: This program is distributed in the hope that it will be useful, paulo@0: but WITHOUT ANY WARRANTY; without even the implied warranty of paulo@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the paulo@0: GNU General Public License for more details. paulo@0: paulo@0: You should have received a copy of the GNU General Public License paulo@0: along with this program; if not, write to the Free Software paulo@0: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA paulo@0: paulo@0: Original game concept and design by Alexey Pajitnov. paulo@0: The Software is not sponsored or endorsed by Alexey Pajitnov, Elorg, paulo@0: or The Tetris Company LLC. paulo@0: paulo@0: */ paulo@0: paulo@0: #include paulo@0: #include paulo@0: #include "ljgba.h" paulo@0: #include "ljplay.h" paulo@0: #include "options.h" paulo@0: paulo@0: #if 1 paulo@0: #define LJ_VERSION "0.46 ("__DATE__")" paulo@0: #else paulo@0: #define LJ_VERSION "WIP ("__DATE__")" paulo@0: #endif paulo@0: paulo@0: #define SCREEN_W 30 paulo@0: #define SCREEN_H 20 paulo@0: #define DS_PFTOP 0 paulo@0: #define DS_PFLEFT 9 paulo@0: #include "ljgbads.inc" paulo@0: paulo@0: static unsigned int nSprites; paulo@0: paulo@0: LJBits readHWKeys(void) { paulo@0: return (~REG_KEYINPUT) & 0x03FF; paulo@0: } paulo@0: paulo@0: void finishSprites() { paulo@0: for (int i = nSprites - 1; i >= 0; --i) { paulo@0: OAM[i].attr0 = 512; paulo@0: } paulo@0: nSprites = 128; paulo@0: } paulo@0: paulo@0: void vsync(void) { paulo@0: VBlankIntrWait(); paulo@0: } paulo@0: paulo@0: void openWindow(void) { paulo@0: REG_DISPCNT = MODE_0 | BG0_ON | OBJ_ON; paulo@0: BGCTRL[0] = BG_TILE_BASE(0) | BG_MAP_BASE(31); paulo@0: BG_PALETTE[0] = RGB5(31, 31, 31); paulo@0: BG_PALETTE[1] = RGB5(0, 0, 0); paulo@0: SPRITE_PALETTE[0] = RGB5(31, 0, 31); paulo@0: SPRITE_PALETTE[1] = RGB5(0, 0, 0); paulo@0: setupPalette(srsColors); paulo@0: } paulo@0: paulo@0: void playSoundEffects(LJView *v, LJBits sounds, int countdown) { paulo@0: if (sounds & LJSND_IRS) { paulo@0: gba_play_sound(v->plat, 6); paulo@0: } else if (sounds & LJSND_ROTATE) { paulo@0: gba_play_sound(v->plat, 1); paulo@0: } paulo@0: if (sounds & LJSND_SHIFT) { paulo@0: gba_play_sound(v->plat, 0); paulo@0: } paulo@0: if (sounds & LJSND_LAND) { paulo@0: gba_play_sound(v->plat, 2); paulo@0: } paulo@0: if (sounds & LJSND_LOCK) { paulo@0: gba_play_sound(v->plat, 3); paulo@0: } paulo@0: if (sounds & LJSND_B2B) { paulo@0: gba_play_sound(v->plat, 8); paulo@0: } else if (sounds & LJSND_SETB2B) { paulo@0: gba_play_sound(v->plat, 7); paulo@0: } else if (sounds & LJSND_LINE) { paulo@0: gba_play_sound(v->plat, 4); paulo@0: } paulo@0: if (sounds & LJSND_HOLD) { paulo@0: gba_play_sound(v->plat, 5); paulo@0: } paulo@0: if (sounds & LJSND_SECTIONUP) { paulo@0: gba_play_sound(v->plat, 9); paulo@0: } paulo@0: gba_poll_sound(v->plat); paulo@0: } paulo@0: paulo@0: /** paulo@0: * Draws a tetromino whose lower left corner of the bounding box is at (x, y) paulo@0: * @param b the bitmap to draw to paulo@0: * @param piece the piece to be drawn paulo@0: * @param x distance from to left side of 4x4 box paulo@0: * @param y distance from top of bitmap to bottom of 4x4 box paulo@0: * @param the rotation state (0: U; 1: R; 2: D; 3: L; 4: Initial position) paulo@0: * @param w width of each block paulo@0: * @param h height of each block paulo@0: * @param color Drawing style paulo@0: * color == 0: draw shadow paulo@0: * color == 0x10 through 0x70: draw in that color paulo@0: * color == 0x80: draw as garbage paulo@0: * color == -255 through -1: draw with 255 through 1 percent lighting paulo@0: */ paulo@0: LJBits drawPiece(LJView *const v, void *const b, paulo@0: int piece, int x, int y, int theta, paulo@0: int color, int w, int h) { paulo@0: // Don't try to draw the -1 that's the sentinel for no hold piece paulo@0: if (piece < 0) paulo@0: return 0; paulo@0: paulo@0: LJBits rows = 0; paulo@0: LJBlkSpec blocks[4]; paulo@0: paulo@0: expandPieceToBlocks(blocks, v->field, piece, 0, 0, theta); paulo@0: paulo@0: for (int blk = 0; blk < 4; ++blk) { paulo@0: int blkValue = blocks[blk].conn; paulo@0: if (blkValue) { paulo@0: int blkX = blocks[blk].x; paulo@0: int blkY = blocks[blk].y; paulo@0: const int dstX = x + w * blkX; paulo@0: const int dstY = y + h * (-1 - blkY); paulo@0: paulo@0: if (color == 0x80) { paulo@0: blkValue = 0x8001; // garbage hold paulo@0: } else if (color != 0) { paulo@0: blkValue = ((blkValue & 0xF0) << 8) | 1; paulo@0: } else if (color == 0) { paulo@0: if (v->hideShadow == LJSHADOW_COLORED) { paulo@0: blkValue = ((blkValue & 0xF0) << 8) | 2; paulo@0: } else { paulo@0: blkValue = 0x0002; paulo@0: } paulo@0: } paulo@0: paulo@0: if (dstY > -8 && dstY < 160) { paulo@0: --nSprites; paulo@0: OAM[nSprites].attr0 = dstY & 0x00FF; paulo@0: OAM[nSprites].attr1 = dstX & 0x01FF; paulo@0: OAM[nSprites].attr2 = blkValue; paulo@0: } paulo@0: paulo@0: rows |= 1 << blkY; paulo@0: } paulo@0: } paulo@0: paulo@0: return rows; paulo@0: } paulo@0: paulo@0: extern unsigned char prefs[OPTIONS_MENU_LEN]; paulo@0: paulo@0: #include "gbamenus.h" paulo@0: paulo@0: int main(void) { paulo@0: LJField p = { paulo@0: .leftWall = 1, paulo@0: .rightWall = 11, paulo@0: .ceiling = 20 paulo@0: }; paulo@0: LJControl control = { paulo@0: .dasSpeed = 1, paulo@0: .dasDelay = 10, paulo@0: .initialDAS = 1, paulo@0: .allowDiagonals = 0, paulo@0: .softDropSpeed = 0, paulo@0: .softDropLock = 0, paulo@0: .hardDropLock = 1 paulo@0: }; paulo@0: struct LJPCView platView; paulo@0: LJView mainView = { paulo@0: .field = &p, paulo@0: .control = &control, paulo@0: .smoothGravity = 1, paulo@0: .plat = &platView, paulo@0: .backDirty = ~0 paulo@0: }; paulo@0: paulo@0: videoSetMode(MODE_0_2D); paulo@0: BG_PALETTE[0] = RGB5(31, 0, 0); paulo@0: install_timer(); paulo@0: openWindow(); paulo@0: install_sound(&platView); paulo@0: initOptions(customPrefs); paulo@0: coprNotice(); paulo@0: paulo@0: while (1) { paulo@0: LJView *const players[1] = {&mainView}; paulo@0: REG_DISPCNT = MODE_0 | BG0_ON; paulo@0: BG_PALETTE[0] = RGB5(31, 31, 31); paulo@0: setupPalette(srsColors); paulo@0: options(&mainView, customPrefs); paulo@0: unpackCommonOptions(&mainView, customPrefs); paulo@0: paulo@0: p.seed = curTime ^ (curTime << 16); paulo@0: play(players, 1); paulo@0: BG_PALETTE[0] = (control.countdown > 0) paulo@0: ? RGB5(31, 15, 15) paulo@0: : RGB5(15, 31, 15); paulo@0: if (control.countdown > 0) { paulo@0: gba_play_sound(&platView, 10); paulo@0: gba_play_sound(&platView, 11); paulo@0: } else { paulo@0: gba_play_sound(&platView, 12); paulo@0: gba_play_sound(&platView, 13); paulo@0: } paulo@0: for (int i = 0; i < 60; ++i) { paulo@0: vsync(); paulo@0: gba_poll_sound(&platView); paulo@0: } paulo@0: #if 1 paulo@0: debrief(&mainView); paulo@0: #else paulo@0: textout(" Press ", (SCREEN_W - 8) / 2, DS_PFTOP + 8, 0); paulo@0: textout(" Start ", (SCREEN_W - 8) / 2, DS_PFTOP + 9, 0); paulo@0: waitForStart(); paulo@0: #endif paulo@0: } paulo@0: }