view src/ljds.c @ 1:38c62fded078

initial builds (linux and lj.nds)
author paulo@localhost
date Fri, 13 Mar 2009 01:10:13 -0700
parents
children
line source
1 /* DS frontend for LOCKJAW, an implementation of the Soviet Mind Game
3 Copyright (C) 2006-2007 Damian Yerrick <tepples+lj@spamcop.net>
5 This work is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 Original game concept and design by Alexey Pajitnov.
20 The Software is not sponsored or endorsed by Alexey Pajitnov, Elorg,
21 or The Tetris Company LLC.
23 */
25 #include "ljplay.h"
26 #include "ljds.h"
27 #include "talkback.h"
28 #include <stdio.h>
29 #include <string.h>
30 #include "options.h"
31 #include "gbamenus.h"
32 #include "ljpath.h"
34 #if 1
35 #define LJ_VERSION "0.46 ("__DATE__")"
36 #else
37 #define LJ_VERSION "WIP ("__DATE__")"
38 #endif
40 #define SCREEN_W 32
41 #define SCREEN_H 24
42 #define DS_PFTOP 3
43 #define DS_PFLEFT 10
45 /* My ghetto IPC system */
46 volatile P8A7Talkback tb_cached = {
47 .cmd = 0,
48 .sounds = 0
49 };
51 #define tb (*(volatile P8A7Talkback *) \
52 ((volatile char *)&tb_cached + 0x00400000))
54 short mouse_x, mouse_y;
55 LJBits mouse_b;
57 #include "ljgbads.inc"
59 unsigned int nSprites = 0;
60 volatile int curTime;
62 void gba_play_sound(struct LJPCView *v, int n) {
64 }
66 void gba_poll_sound(struct LJPCView *plat) {
68 }
70 LJBits readHWKeys(void) {
71 scanKeys();
72 LJBits j = keysHeld();
73 touchPosition xy = touchReadXY();
75 if (j & KEY_TOUCH) {
76 mouse_x = xy.px;
77 mouse_y = xy.py;
78 mouse_b = 1;
79 j &= ~(KEY_TOUCH_RIGHT | KEY_TOUCH_LEFT
80 | KEY_TOUCH_UP | KEY_TOUCH_DOWN);
81 if (xy.px < 96) {
82 j |= KEY_TOUCH_LEFT;
83 } else if (xy.px >= 160) {
84 j |= KEY_TOUCH_RIGHT;
85 }
86 if (xy.py < 64) {
87 j |= KEY_TOUCH_UP;
88 } else if (xy.py >= 128) {
89 j |= KEY_TOUCH_DOWN;
90 }
91 } else {
92 mouse_b = 0;
93 }
94 return j;
95 }
97 void finishSprites(void) {
98 for (int i = nSprites - 1; i >= 0; --i) {
99 MAINOAM[i].attribute[0] = 512;
100 }
101 nSprites = 128;
102 }
104 void vsync(void) {
105 swiWaitForVBlank();
106 wantPause |= needLidSleep();
107 }
109 void isr(void)
110 {
111 int interrupts = REG_IF;
113 VBLANK_INTR_WAIT_FLAGS |= interrupts;
114 REG_IF = interrupts;
115 ++curTime;
116 }
118 #define KEY_X (IPC_X << 16)
119 #define KEY_Y (IPC_Y << 16)
120 #define KEY_PEN (IPC_PEN_DOWN << 16)
121 #define VRAM_MAIN ((uint16 *)0x06000000)
122 #define VRAM_SUB ((uint16 *)0x06200000)
126 /**
127 * Tells the ARM7 to play these sound effects.
128 */
129 void playSoundEffects(LJView *v, LJBits sounds, int countdown) {
130 tb.countdown = countdown;
131 tb.sounds |= sounds;
132 }
134 #define SHADOW_BLOCK 0x00
136 /**
137 * Draws a tetromino whose lower left corner of the bounding box is at (x, y)
138 * @param b the bitmap to draw to
139 * @param piece the piece to be drawn
140 * @param x distance from to left side of 4x4 box
141 * @param y distance from top of bitmap to bottom of 4x4 box
142 * @param the rotation state (0: U; 1: R; 2: D; 3: L; 4: Initial position)
143 * @param w width of each block
144 * @param h height of each block
145 * @param color Drawing style
146 * color == 0: draw shadow
147 * color == 0x10 through 0x70: draw in that color
148 * color == 0x80: draw as garbage
149 * color == -255 through -1: draw with 255 through 1 percent lighting
150 */
151 LJBits drawPiece(LJView *const v, void *const b,
152 int piece, int x, int y, int theta,
153 int color, int w, int h) {
154 // Don't try to draw the -1 that's the sentinel for no hold piece
155 if (piece < 0)
156 return 0;
158 LJBits rows = 0;
159 LJBlkSpec blocks[4];
161 expandPieceToBlocks(blocks, v->field, piece, 0, 0, theta);
163 for (int blk = 0; blk < 4; ++blk) {
164 int blkValue = blocks[blk].conn;
165 if (blkValue) {
166 int blkX = blocks[blk].x;
167 int blkY = blocks[blk].y;
168 const int dstX = x + w * blkX;
169 const int dstY = y + h * (-1 - blkY);
171 if (color == 0x80) {
172 blkValue = 0x8001; // garbage hold
173 } else if (color != 0) {
174 blkValue = ((blkValue & 0xF0) << 8) | 1;
175 } else if (color == 0) {
176 if (v->hideShadow == LJSHADOW_COLORED) {
177 blkValue = ((blkValue & 0xF0) << 8) | 2;
178 } else {
179 blkValue = 0x8002;
180 }
181 }
183 if (dstY > -8 && dstY < 192) {
184 --nSprites;
185 MAINOAM[nSprites].attribute[0] = dstY & 0x00FF;
186 MAINOAM[nSprites].attribute[1] = dstX & 0x01FF;
187 MAINOAM[nSprites].attribute[2] = blkValue;
188 }
190 rows |= 1 << blkY;
191 }
192 }
194 return rows;
195 }
197 void openWindow(void) {
198 videoSetMode(MODE_0_2D
199 | DISPLAY_BG0_ACTIVE
200 | DISPLAY_SPR_1D_LAYOUT
201 | DISPLAY_SPR_ACTIVE);
202 videoSetModeSub(MODE_0_2D
203 | DISPLAY_BG0_ACTIVE);
204 BGCTRL[0] = BG_16_COLOR | BG_TILE_BASE(0) | BG_MAP_BASE(31);
205 BGCTRL_SUB[0] = BG_16_COLOR | BG_TILE_BASE(0) | BG_MAP_BASE(31);
207 vramSetMainBanks(VRAM_A_MAIN_BG, VRAM_B_MAIN_SPRITE_0x06400000,
208 VRAM_C_SUB_BG, VRAM_D_SUB_SPRITE);
209 /* load_font(); */
210 // Load palette
211 BG_PALETTE[0] = RGB5(31,31,31);
212 BG_PALETTE[1] = RGB5( 0, 0,15);
213 BG_PALETTE_SUB[0] = RGB5(0, 0, 0);
214 setupPalette(srsColors);
216 // Set scrolling
217 BG_OFFSET[0].x = 0;
218 BG_OFFSET[0].y = 0;
219 BG_OFFSET_SUB[0].x = 0;
220 BG_OFFSET_SUB[0].y = 0;
222 SUB_BG2_XDX = 0x100;
223 SUB_BG2_XDY = 0;
224 SUB_BG2_YDX = 0;
225 SUB_BG2_YDY = 0x100;
226 SUB_BG2_CY = 0;
227 SUB_BG2_CX = 0;
229 lcdMainOnTop();
230 }
232 void install_sound(void) {
233 IPC->soundData = (void *)&tb;
234 }
236 #ifdef TRAP_SPRINTF
237 int sprintf (char *dst, const char *format, ...) {
238 BG_PALETTE[0] = RGB5(31, 0, 0);
239 strcpy(dst, "[NO FPU]");
240 return 8;
241 }
242 #endif
244 int main(void) {
245 LJField p = {
246 .leftWall = 1,
247 .rightWall = 11,
248 .ceiling = 20
249 };
250 LJControl control = {
251 .dasSpeed = 1,
252 .dasDelay = 10,
253 .initialDAS = 1,
254 .allowDiagonals = 0,
255 .softDropSpeed = 0,
256 .softDropLock = 0,
257 .hardDropLock = 1
258 };
259 struct LJPCView platView;
260 LJView mainView = {
261 .field = &p,
262 .control = &control,
263 .smoothGravity = 1,
264 .nextPieces = 3,
265 .plat = &platView,
266 .backDirty = ~0
267 };
269 powerON(POWER_ALL_2D);
270 initOptions(customPrefs);
271 install_timer();
272 install_sound();
273 openWindow();
275 BG_PALETTE_SUB[0] = RGB5( 0, 0, 0);
276 BG_PALETTE_SUB[1] = RGB5(10,20,10);
277 BG_PALETTE_SUB[2] = RGB5(15,31,15);
278 BG_PALETTE_SUB[3] = RGB5(15,31,15);
279 vwfWinInit(&vwfTouch);
280 {
281 int x = vwfPuts(&vwfTouch, "finding memory card... ", 0, 0);
282 if (ljpathInit("/data/lockjaw/lj.nds")) {
283 vwfPuts(&vwfTouch, "success!", x, 0);
284 } else {
285 vwfPuts(&vwfTouch, "failed.", x, 0);
286 vwfPuts(&vwfTouch, "To learn how to fix this, see", 0, 12);
287 vwfPuts(&vwfTouch, "http://dldi.drunkencoders.com/", 0, 24);
288 }
289 }
291 coprNotice();
293 load_font();
294 drawFrame(&mainView);
296 while (1) {
297 LJView *const players[1] = {&mainView};
299 for (int y = 0; y < LJ_PF_VIS_HT; ++y) {
300 for (int x = 0; x < LJ_PF_WID; ++x) {
301 p.b[y][x] = 0;
302 }
303 }
304 updField(&mainView, ~0);
306 // turn on sub display only long enough for options
307 videoSetModeSub(MODE_0_2D
308 | DISPLAY_BG0_ACTIVE);
309 setupPalette(srsColors);
310 options(&mainView, customPrefs);
311 videoSetModeSub(MODE_0_2D);
312 BGCTRL_SUB[0] = BG_16_COLOR | BG_TILE_BASE(0) | BG_MAP_BASE(31);
313 BG_PALETTE_SUB[0] = RGB5(0, 0, 0);
314 unpackCommonOptions(&mainView, customPrefs);
316 p.seed = curTime ^ (curTime << 16);
317 play(players, 1);
319 tb.cmd = TALKBACK_STOP_MUSIC;
320 BG_PALETTE[0] = (control.countdown > 0)
321 ? RGB5(31, 15, 15)
322 : RGB5(15, 31, 15);
324 // play game over sound
325 if (control.countdown > 0) {
326 playSoundEffects(&mainView, 3 << 16, control.countdown);
327 }
328 for (int i = 0; i < 60; ++i) {
329 vsync();
330 //gba_poll_sound(&platView);
331 }
332 debrief(&mainView);
333 }
334 }