rev |
line source |
paulo@0
|
1 /* DS/GBA frontend for LOCKJAW, an implementation of the Soviet Mind Game
|
paulo@0
|
2
|
paulo@0
|
3 Copyright (C) 2006-2007 Damian Yerrick <tepples+lj@spamcop.net>
|
paulo@0
|
4
|
paulo@0
|
5 This work is free software; you can redistribute it and/or modify
|
paulo@0
|
6 it under the terms of the GNU General Public License as published by
|
paulo@0
|
7 the Free Software Foundation; either version 2 of the License, or
|
paulo@0
|
8 (at your option) any later version.
|
paulo@0
|
9
|
paulo@0
|
10 This program is distributed in the hope that it will be useful,
|
paulo@0
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
paulo@0
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
paulo@0
|
13 GNU General Public License for more details.
|
paulo@0
|
14
|
paulo@0
|
15 You should have received a copy of the GNU General Public License
|
paulo@0
|
16 along with this program; if not, write to the Free Software
|
paulo@0
|
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
paulo@0
|
18
|
paulo@0
|
19 Original game concept and design by Alexey Pajitnov.
|
paulo@0
|
20 The Software is not sponsored or endorsed by Alexey Pajitnov, Elorg,
|
paulo@0
|
21 or The Tetris Company LLC.
|
paulo@0
|
22
|
paulo@0
|
23 */
|
paulo@0
|
24
|
paulo@0
|
25 #include "fontdraw.h"
|
paulo@0
|
26
|
paulo@0
|
27 unsigned char wantPause;
|
paulo@0
|
28 volatile char redrawWholeScreen = 0;
|
paulo@0
|
29
|
paulo@0
|
30 void finishSprites();
|
paulo@0
|
31
|
paulo@0
|
32 void cls(void) {
|
paulo@0
|
33 for (int y = 0; y < SCREEN_H; ++y) {
|
paulo@0
|
34 for (int x = 0; x < SCREEN_W; ++x) {
|
paulo@0
|
35 MAP[31][y][x] = ' ';
|
paulo@0
|
36 }
|
paulo@0
|
37 }
|
paulo@0
|
38 }
|
paulo@0
|
39
|
paulo@0
|
40 void drawFrame(LJView *v) {
|
paulo@0
|
41 int left = v->field->leftWall;
|
paulo@0
|
42 int right = v->field->rightWall;
|
paulo@0
|
43 cls();
|
paulo@0
|
44 if (DS_PFTOP > 0) {
|
paulo@0
|
45 for (int x = left - 1; x < right + 1; ++x) {
|
paulo@0
|
46 MAP[31][DS_PFTOP - 1][DS_PFLEFT + x] = 0x8005;
|
paulo@0
|
47 }
|
paulo@0
|
48 }
|
paulo@0
|
49 if (DS_PFTOP + LJ_PF_VIS_HT < SCREEN_H) {
|
paulo@0
|
50 for (int x = left - 1; x < right + 1; ++x) {
|
paulo@0
|
51 MAP[31][DS_PFTOP + LJ_PF_VIS_HT][DS_PFLEFT + x] = 0x8004;
|
paulo@0
|
52 }
|
paulo@0
|
53 }
|
paulo@0
|
54 for (int i = 0; i < LJ_PF_VIS_HT; ++i) {
|
paulo@0
|
55 MAP[31][i + DS_PFTOP][DS_PFLEFT + left - 1] = 0x8003;
|
paulo@0
|
56 MAP[31][i + DS_PFTOP][DS_PFLEFT + right] = 0x8003;
|
paulo@0
|
57 }
|
paulo@0
|
58 textout("Score", 1, 6 + DS_PFTOP, 0);
|
paulo@0
|
59 textout("Lines", 1, 8 + DS_PFTOP, 0);
|
paulo@0
|
60 textout("Speed", 1, 10 + DS_PFTOP, 0);
|
paulo@0
|
61 }
|
paulo@0
|
62
|
paulo@0
|
63 static void drawBlock(struct LJPCView *unused, int x, int y, int b) {
|
paulo@0
|
64 if (x >= 0 && x < LJ_PF_WID && y >= 0 && y < LJ_PF_VIS_HT) {
|
paulo@0
|
65 int c;
|
paulo@0
|
66
|
paulo@0
|
67 if (b == 0x100) {
|
paulo@0
|
68 c = '-';
|
paulo@0
|
69 } else if (b == 0x110) {
|
paulo@0
|
70 c = 0x8005; // ceiling tile
|
paulo@0
|
71 } else if (b >= 0xA0 && b < 0xC0) {
|
paulo@0
|
72 c = (b & 0xF0) << 8 | (b & 0x0F) | 0x100;
|
paulo@0
|
73 } else if (b >= 0x10) {
|
paulo@0
|
74 c = (b & 0xF0) << 8 | (b & 0x0F) | 0x10;
|
paulo@0
|
75 } else {
|
paulo@0
|
76 c = ' ';
|
paulo@0
|
77 }
|
paulo@0
|
78 MAP[31][DS_PFTOP + LJ_PF_VIS_HT - 1 - y][DS_PFLEFT + x] = c;
|
paulo@0
|
79 }
|
paulo@0
|
80 }
|
paulo@0
|
81
|
paulo@0
|
82 void updField(const LJView *const v, LJBits rows) {
|
paulo@0
|
83 const LJField *const p = v->field;
|
paulo@0
|
84
|
paulo@0
|
85 for (int y = 0;
|
paulo@0
|
86 y < LJ_PF_VIS_HT && rows != 0;
|
paulo@0
|
87 ++y, rows >>= 1) {
|
paulo@0
|
88 int blankTile = 0;
|
paulo@0
|
89
|
paulo@0
|
90 if (y == p->ceiling) {
|
paulo@0
|
91 blankTile = 0x110;
|
paulo@0
|
92 } else if (hotlineRows[y] && v->field->scoreStyle == LJSCORE_HOTLINE) {
|
paulo@0
|
93 blankTile = 0x100;
|
paulo@0
|
94 }
|
paulo@0
|
95 if (p->state == LJS_LINES_FALLING && p->stateTime > 0
|
paulo@0
|
96 && ((1 << y) & p->tempRows)) {
|
paulo@0
|
97 blankTile = 0x100;
|
paulo@0
|
98 }
|
paulo@0
|
99 if (rows & 1) {
|
paulo@0
|
100 for (int x = p->leftWall; x < p->rightWall; x++) {
|
paulo@0
|
101 int b = v->hidePF ? 0 : p->b[y][x];
|
paulo@0
|
102 drawBlock(v->plat, x, y, b ? b : blankTile);
|
paulo@0
|
103 }
|
paulo@0
|
104 }
|
paulo@0
|
105 }
|
paulo@0
|
106 }
|
paulo@0
|
107
|
paulo@0
|
108 void blitField(LJView *v) {
|
paulo@0
|
109
|
paulo@0
|
110 }
|
paulo@0
|
111
|
paulo@0
|
112 int getTime() {
|
paulo@0
|
113 return curTime;
|
paulo@0
|
114 }
|
paulo@0
|
115
|
paulo@0
|
116 #if !defined(DISP_VBLANK_IRQ)
|
paulo@0
|
117 #define DISP_VBLANK_IRQ LCDC_VBL
|
paulo@0
|
118 #endif
|
paulo@0
|
119 #if !defined(IRQ_HANDLER)
|
paulo@0
|
120 #define IRQ_HANDLER INT_VECTOR
|
paulo@0
|
121 #endif
|
paulo@0
|
122
|
paulo@0
|
123 void install_timer(void)
|
paulo@0
|
124 {
|
paulo@0
|
125
|
paulo@0
|
126 // Turn off interrupts before doing anything
|
paulo@0
|
127 REG_IME = 0;
|
paulo@0
|
128
|
paulo@0
|
129 // Overwrite the ISR
|
paulo@0
|
130 IRQ_HANDLER = isr;
|
paulo@0
|
131
|
paulo@0
|
132 // Hook up the interrupt destination
|
paulo@0
|
133 REG_IE = IRQ_VBLANK;
|
paulo@0
|
134
|
paulo@0
|
135 // Acknowledge all pending interrupts
|
paulo@0
|
136 REG_IF = ~0;
|
paulo@0
|
137
|
paulo@0
|
138 // Set up an interrupt source
|
paulo@0
|
139 REG_DISPSTAT = DISP_VBLANK_IRQ;
|
paulo@0
|
140
|
paulo@0
|
141 // Turn interrupts back on
|
paulo@0
|
142 REG_IME = 1;
|
paulo@0
|
143 }
|
paulo@0
|
144
|
paulo@0
|
145 void yieldCPU(void) {
|
paulo@0
|
146 // we're not multitasking so we don't need this
|
paulo@0
|
147 // on the GBA and DS, vsync() does all the waiting we need
|
paulo@0
|
148 }
|
paulo@0
|
149
|
paulo@0
|
150 static void upcvt_4bit(void *dst, const u8 *src, size_t len)
|
paulo@0
|
151 {
|
paulo@0
|
152 u32 *out = dst;
|
paulo@0
|
153
|
paulo@0
|
154 for(; len > 0; len--)
|
paulo@0
|
155 {
|
paulo@0
|
156 u32 dst_bits = 0;
|
paulo@0
|
157 u32 src_bits = *src++;
|
paulo@0
|
158 u32 x;
|
paulo@0
|
159
|
paulo@0
|
160 for(x = 0; x < 8; x++)
|
paulo@0
|
161 {
|
paulo@0
|
162 dst_bits <<= 4;
|
paulo@0
|
163 dst_bits |= src_bits & 1;
|
paulo@0
|
164 src_bits >>= 1;
|
paulo@0
|
165 }
|
paulo@0
|
166 *out++ = dst_bits;
|
paulo@0
|
167 }
|
paulo@0
|
168 }
|
paulo@0
|
169
|
paulo@0
|
170 extern const unsigned char text_chr[];
|
paulo@0
|
171 extern const unsigned int text_chr_size;
|
paulo@0
|
172 extern const unsigned char gbablk_chr[];
|
paulo@0
|
173 extern const unsigned int gbablk_chr_size;
|
paulo@0
|
174
|
paulo@0
|
175 static void loadOneConnection(void *in_dst, const void *in_src) {
|
paulo@0
|
176 u16 *dst = in_dst;
|
paulo@0
|
177 const u16 *src = in_src;
|
paulo@0
|
178 for (unsigned int conn = 0; conn < 16; ++conn) {
|
paulo@0
|
179 unsigned int topSegY = (conn & CONNECT_U) ? 32 : 0;
|
paulo@0
|
180 unsigned int botSegY = (conn & CONNECT_D) ? 8 : 40;
|
paulo@0
|
181 unsigned int leftSegX = (conn & CONNECT_L) ? 16 : 0;
|
paulo@0
|
182 unsigned int rightSegX = (conn & CONNECT_R) ? 1 : 17;
|
paulo@0
|
183 for (unsigned int i = 0; i < 8; i += 2) {
|
paulo@0
|
184 *dst++ = src[leftSegX + topSegY + i];
|
paulo@0
|
185 *dst++ = src[rightSegX + topSegY + i];
|
paulo@0
|
186 }
|
paulo@0
|
187 for (unsigned int i = 0; i < 8; i += 2) {
|
paulo@0
|
188 *dst++ = src[leftSegX + botSegY + i];
|
paulo@0
|
189 *dst++ = src[rightSegX + botSegY + i];
|
paulo@0
|
190 }
|
paulo@0
|
191 }
|
paulo@0
|
192 }
|
paulo@0
|
193
|
paulo@0
|
194 static void loadConnections(void) {
|
paulo@0
|
195 loadOneConnection(PATRAM4(0, 16), gbablk_chr + 8*32);
|
paulo@0
|
196 loadOneConnection(PATRAM4(0, 256), gbablk_chr + 12*32);
|
paulo@0
|
197 }
|
paulo@0
|
198
|
paulo@0
|
199 static void load_font(void) {
|
paulo@0
|
200 upcvt_4bit(PATRAM4(0, 0), text_chr, text_chr_size);
|
paulo@0
|
201 memcpy(PATRAM4(0, 0), gbablk_chr, 8*32);
|
paulo@0
|
202 memcpy(SPR_VRAM(0), gbablk_chr, 8*32);
|
paulo@0
|
203 loadConnections();
|
paulo@0
|
204 }
|
paulo@0
|
205
|
paulo@0
|
206 void textout(const char *str, int x, int y, int c) {
|
paulo@0
|
207 u16 *dst = &(MAP[31][y][x]);
|
paulo@0
|
208 int spacesLeft = SCREEN_W - x;
|
paulo@0
|
209
|
paulo@0
|
210 c <<= 12;
|
paulo@0
|
211 while (*str != 0 && spacesLeft > 0) {
|
paulo@0
|
212 *dst++ = c | *(unsigned char *)str++;
|
paulo@0
|
213 --spacesLeft;
|
paulo@0
|
214 }
|
paulo@0
|
215 }
|
paulo@0
|
216
|
paulo@0
|
217 static const u16 srsColors[12] = {
|
paulo@0
|
218 RGB5(2, 2, 2),
|
paulo@0
|
219 RGB5(0, 3, 3),
|
paulo@0
|
220 RGB5(0, 0, 3),
|
paulo@0
|
221 RGB5(3, 2, 0),
|
paulo@0
|
222 RGB5(3, 3, 0),
|
paulo@0
|
223 RGB5(0, 3, 0),
|
paulo@0
|
224 RGB5(2, 0, 3),
|
paulo@0
|
225 RGB5(3, 0, 0),
|
paulo@0
|
226 RGB5(2, 2, 2),
|
paulo@0
|
227 RGB5(3, 0, 0),
|
paulo@0
|
228 RGB5(2, 2, 2),
|
paulo@0
|
229 RGB5(3, 2, 1),
|
paulo@0
|
230 };
|
paulo@0
|
231
|
paulo@0
|
232 static const u16 arsColors[12] = {
|
paulo@0
|
233 RGB5(2, 2, 2),
|
paulo@0
|
234 RGB5(3, 1, 0),
|
paulo@0
|
235 RGB5(0, 0, 3),
|
paulo@0
|
236 RGB5(3, 2, 0),
|
paulo@0
|
237 RGB5(3, 3, 0),
|
paulo@0
|
238 RGB5(2, 0, 3),
|
paulo@0
|
239 RGB5(0, 3, 3),
|
paulo@0
|
240 RGB5(0, 3, 0),
|
paulo@0
|
241 RGB5(2, 2, 2),
|
paulo@0
|
242 RGB5(3, 0, 0),
|
paulo@0
|
243 RGB5(2, 2, 2),
|
paulo@0
|
244 RGB5(3, 2, 1),
|
paulo@0
|
245 };
|
paulo@0
|
246
|
paulo@0
|
247 void setupPalette(const u16 *colors) {
|
paulo@0
|
248 for (int i = 1; i < 12; ++i) {
|
paulo@0
|
249 int c = colors[i];
|
paulo@0
|
250
|
paulo@0
|
251 BG_PALETTE[i * 16 + 1] = RGB5(22,22,22) + 3 * c;
|
paulo@0
|
252 BG_PALETTE[i * 16 + 2] = RGB5(13,13,13) + 6 * c;
|
paulo@0
|
253 BG_PALETTE[i * 16 + 3] = RGB5( 4, 4, 4) + 9 * c;
|
paulo@0
|
254 BG_PALETTE[i * 16 + 4] = RGB5( 4, 4, 4) + 7 * c;
|
paulo@0
|
255 BG_PALETTE[i * 16 + 5] = RGB5( 4, 4, 4) + 5 * c;
|
paulo@0
|
256 BG_PALETTE[i * 16 + 6] = RGB5( 4, 4, 4) + 3 * c;
|
paulo@0
|
257 }
|
paulo@0
|
258 memcpy(SPRITE_PALETTE, BG_PALETTE, 12 * 32);
|
paulo@0
|
259 }
|
paulo@0
|
260
|
paulo@0
|
261 // libnds style wrapper around libgba header
|
paulo@0
|
262 #ifndef DISPLAY_BG0_ACTIVE
|
paulo@0
|
263 #define DISPLAY_BG0_ACTIVE BG0_ON
|
paulo@0
|
264 #define DISPLAY_SPR_ACTIVE OBJ_ON
|
paulo@0
|
265 #define MODE_0_2D MODE_0
|
paulo@0
|
266 #define DISPLAY_SPR_1D_LAYOUT OBJ_1D_MAP
|
paulo@0
|
267 static inline void videoSetMode(int x) {
|
paulo@0
|
268 REG_DISPCNT = x;
|
paulo@0
|
269 }
|
paulo@0
|
270
|
paulo@0
|
271 #endif
|
paulo@0
|
272
|
paulo@0
|
273 void waitForStart(void) {
|
paulo@0
|
274 LJBits lastJ = ~0;
|
paulo@0
|
275 LJBits jnew = 0;
|
paulo@0
|
276
|
paulo@0
|
277 do {
|
paulo@0
|
278 LJBits j = ~REG_KEYINPUT;
|
paulo@0
|
279 jnew = j & ~lastJ;
|
paulo@0
|
280 lastJ = j;
|
paulo@0
|
281 vsync();
|
paulo@0
|
282 } while(!(jnew & (KEY_A | KEY_START)));
|
paulo@0
|
283 }
|
paulo@0
|
284
|
paulo@0
|
285
|
paulo@0
|
286 static const char *const coprNoticeLines[] = {
|
paulo@0
|
287 "LOCKJAW: The Reference",
|
paulo@0
|
288 "Version "LJ_VERSION,
|
paulo@0
|
289 NULL,
|
paulo@0
|
290 "© 2008 Damian Yerrick",
|
paulo@0
|
291 "Not sponsored or endorsed by Nintendo",
|
paulo@0
|
292 "or Tetris Holding.",
|
paulo@0
|
293 "Comes with ABSOLUTELY NO WARRANTY.",
|
paulo@0
|
294 "This is free software, and you are welcome",
|
paulo@0
|
295 "to share it under the conditions described",
|
paulo@0
|
296 "in GPL.txt."
|
paulo@0
|
297 };
|
paulo@0
|
298
|
paulo@0
|
299 void coprNotice(void) {
|
paulo@0
|
300 videoSetMode(MODE_0_2D);
|
paulo@0
|
301 BGCTRL[0] = BG_TILE_BASE(0) | BG_MAP_BASE(31);
|
paulo@0
|
302 BG_OFFSET[0].x = 0;
|
paulo@0
|
303 BG_OFFSET[0].y = 0;
|
paulo@0
|
304
|
paulo@0
|
305 BG_PALETTE[0] = RGB5(31,31,31);
|
paulo@0
|
306 BG_PALETTE[1] = RGB5(20,20,20);
|
paulo@0
|
307 BG_PALETTE[2] = RGB5( 0, 0, 0);
|
paulo@0
|
308 vwfWinInit(&vwfTop);
|
paulo@0
|
309 for (int i = 0, y = 8;
|
paulo@0
|
310 i < sizeof(coprNoticeLines) / sizeof(coprNoticeLines[0]);
|
paulo@0
|
311 ++i) {
|
paulo@0
|
312 if (coprNoticeLines[i]) {
|
paulo@0
|
313 vwfPuts(&vwfTop, coprNoticeLines[i], 8, y);
|
paulo@0
|
314 y += 12;
|
paulo@0
|
315 } else {
|
paulo@0
|
316 y += 6;
|
paulo@0
|
317 }
|
paulo@0
|
318 }
|
paulo@0
|
319 vwfPuts(&vwfTop, "Press Start", 8, SCREEN_H * 8 - 16);
|
paulo@0
|
320 videoSetMode(MODE_0_2D | DISPLAY_BG0_ACTIVE);
|
paulo@0
|
321 waitForStart();
|
paulo@0
|
322 }
|
paulo@0
|
323
|
paulo@0
|
324 LJBits menuReadPad(void) {
|
paulo@0
|
325 LJBits keys = readPad(0);
|
paulo@0
|
326 if (keys & VKEY_START) {
|
paulo@0
|
327 keys |= VKEY_ROTR;
|
paulo@0
|
328 }
|
paulo@0
|
329 return keys;
|
paulo@0
|
330 }
|
paulo@0
|
331
|
paulo@0
|
332 void ljBeginDraw(LJView *v, int sync) {
|
paulo@0
|
333 vsync();
|
paulo@0
|
334 finishSprites();
|
paulo@0
|
335 }
|
paulo@0
|
336
|
paulo@0
|
337 void ljEndDraw(LJView *v) {
|
paulo@0
|
338
|
paulo@0
|
339 }
|
paulo@0
|
340
|
paulo@0
|
341 /* Replay stubs */
|
paulo@0
|
342 void replayRecord(struct LJReplay *r, LJBits keys, const LJInput *in) {
|
paulo@0
|
343
|
paulo@0
|
344 }
|
paulo@0
|
345
|
paulo@0
|
346 void replayClose(struct LJReplay *r) {
|
paulo@0
|
347
|
paulo@0
|
348 }
|
paulo@0
|
349
|
paulo@0
|
350 int getReplayFrame(struct LJReplay *r, LJInput *d) {
|
paulo@0
|
351 return 0;
|
paulo@0
|
352 }
|
paulo@0
|
353
|
paulo@0
|
354 #define READY_GO_LINE 13
|
paulo@0
|
355
|
paulo@0
|
356 void startingAnimation(LJView *v) {
|
paulo@0
|
357 vsync();
|
paulo@0
|
358 gba_poll_sound(v->plat);
|
paulo@0
|
359 setupPalette(rotSystems[v->field->rotationSystem]->colorScheme ? arsColors : srsColors);
|
paulo@0
|
360 videoSetMode(MODE_0_2D);
|
paulo@0
|
361 cls();
|
paulo@0
|
362 load_font();
|
paulo@0
|
363 BG_PALETTE[0] = RGB5(31,31,31);
|
paulo@0
|
364 BG_PALETTE[1] = RGB5( 0, 0, 0);
|
paulo@0
|
365 drawFrame(v);
|
paulo@0
|
366 finishSprites();
|
paulo@0
|
367 vsync();
|
paulo@0
|
368 gba_poll_sound(v->plat);
|
paulo@0
|
369 videoSetMode(MODE_0_2D
|
paulo@0
|
370 | DISPLAY_BG0_ACTIVE);
|
paulo@0
|
371 BGCTRL[0] = BG_TILE_BASE(0) | BG_MAP_BASE(31);
|
paulo@0
|
372 BG_OFFSET[0].x = 0;
|
paulo@0
|
373 BG_OFFSET[0].y = 0;
|
paulo@0
|
374
|
paulo@0
|
375 textout("Ready",
|
paulo@0
|
376 (LJ_PF_WID - 5) / 2 + DS_PFLEFT,
|
paulo@0
|
377 DS_PFTOP + LJ_PF_VIS_HT - 1 - READY_GO_LINE,
|
paulo@0
|
378 0);
|
paulo@0
|
379 for (int i = 0; i < 30; ++i) {
|
paulo@0
|
380 vsync();
|
paulo@0
|
381 gba_poll_sound(v->plat);
|
paulo@0
|
382 }
|
paulo@0
|
383 v->backDirty = ~0;
|
paulo@0
|
384 updField(v, ~0);
|
paulo@0
|
385 videoSetMode(MODE_0_2D
|
paulo@0
|
386 | DISPLAY_BG0_ACTIVE
|
paulo@0
|
387 | DISPLAY_SPR_1D_LAYOUT
|
paulo@0
|
388 | DISPLAY_SPR_ACTIVE);
|
paulo@0
|
389 drawScore(v);
|
paulo@0
|
390 finishSprites();
|
paulo@0
|
391
|
paulo@0
|
392 textout(" GO! ",
|
paulo@0
|
393 (LJ_PF_WID - 5) / 2 + DS_PFLEFT,
|
paulo@0
|
394 DS_PFTOP + LJ_PF_VIS_HT - 1 - READY_GO_LINE,
|
paulo@0
|
395 0);
|
paulo@0
|
396 for (int i = 0; i < 30; ++i) {
|
paulo@0
|
397 vsync();
|
paulo@0
|
398 gba_poll_sound(v->plat);
|
paulo@0
|
399 }
|
paulo@0
|
400 drawFrame(v);
|
paulo@0
|
401 wantPause = 0;
|
paulo@0
|
402
|
paulo@0
|
403 #ifdef ARM9
|
paulo@0
|
404 tb.cmd = TALKBACK_PLAY_MUSIC;
|
paulo@0
|
405 #endif
|
paulo@0
|
406 }
|
paulo@0
|
407
|
paulo@0
|
408 int pauseGame(struct LJPCView *v) {
|
paulo@0
|
409 LJBits lastKeys = ~0;
|
paulo@0
|
410 int unpaused = 0;
|
paulo@0
|
411 int canceled = 0;
|
paulo@0
|
412
|
paulo@0
|
413 // hide playfield
|
paulo@0
|
414 for (int y = DS_PFTOP; y < DS_PFTOP + LJ_PF_VIS_HT; ++y) {
|
paulo@0
|
415 for (int x = DS_PFLEFT;
|
paulo@0
|
416 x < DS_PFLEFT + LJ_PF_WID;
|
paulo@0
|
417 ++x) {
|
paulo@0
|
418 MAP[31][y][x] = ' ';
|
paulo@0
|
419 }
|
paulo@0
|
420 }
|
paulo@0
|
421 textout("Game", 2 + DS_PFLEFT, 6 + DS_PFTOP, 0);
|
paulo@0
|
422 textout("Paused", 2 + DS_PFLEFT, 7 + DS_PFTOP, 0);
|
paulo@0
|
423 textout("Start:", 2 + DS_PFLEFT, 10 + DS_PFTOP, 0);
|
paulo@0
|
424 textout("Resume", 2 + DS_PFLEFT, 11 + DS_PFTOP, 0);
|
paulo@0
|
425 textout("Select:", 2 + DS_PFLEFT, 13 + DS_PFTOP, 0);
|
paulo@0
|
426 textout("Exit", 2 + DS_PFLEFT, 14 + DS_PFTOP, 0);
|
paulo@0
|
427
|
paulo@0
|
428 #ifdef ARM9
|
paulo@0
|
429 tb.cmd = TALKBACK_PAUSE_MUSIC;
|
paulo@0
|
430 #endif
|
paulo@0
|
431 while (!unpaused || (lastKeys & (KEY_SELECT | KEY_START))) {
|
paulo@0
|
432 int keys = ~REG_KEYINPUT;
|
paulo@0
|
433 if (keys & ~lastKeys & KEY_START) {
|
paulo@0
|
434 unpaused = 1;
|
paulo@0
|
435 }
|
paulo@0
|
436 if (keys & ~lastKeys & KEY_SELECT) {
|
paulo@0
|
437 unpaused = 1;
|
paulo@0
|
438 canceled = 1;
|
paulo@0
|
439 }
|
paulo@0
|
440 finishSprites();
|
paulo@0
|
441 vsync();
|
paulo@0
|
442 gba_poll_sound(v);
|
paulo@0
|
443 lastKeys = keys;
|
paulo@0
|
444 }
|
paulo@0
|
445 #ifdef ARM9
|
paulo@0
|
446 tb.cmd = TALKBACK_PLAY_MUSIC;
|
paulo@0
|
447 #endif
|
paulo@0
|
448 return canceled;
|
paulo@0
|
449 }
|
paulo@0
|
450
|
paulo@0
|
451 int ljHandleConsoleButtons(LJView *v) {
|
paulo@0
|
452 LJBits keys = ~REG_KEYINPUT;
|
paulo@0
|
453 int canceled = 0;
|
paulo@0
|
454
|
paulo@0
|
455 wantPause |= !!(keys & KEY_START);
|
paulo@0
|
456 if (wantPause) {
|
paulo@0
|
457 canceled = pauseGame(v->plat);
|
paulo@0
|
458 wantPause = 0;
|
paulo@0
|
459 drawFrame(v);
|
paulo@0
|
460 v->backDirty = ~0;
|
paulo@0
|
461 }
|
paulo@0
|
462 return canceled;
|
paulo@0
|
463 }
|
paulo@0
|
464
|
paulo@0
|
465 LJBits drawPiece(LJView *const v, void *const b,
|
paulo@0
|
466 int piece, int x, int y, int theta,
|
paulo@0
|
467 int color, int w, int h);
|
paulo@0
|
468
|
paulo@0
|
469 void drawFallingPiece(LJView *v) {
|
paulo@0
|
470 LJBits bits = 0;
|
paulo@0
|
471 const LJField *const p = v->field;
|
paulo@0
|
472 int piece = p->curPiece[0];
|
paulo@0
|
473 int y = ljfixfloor(p->y);
|
paulo@0
|
474 const int w = 8;
|
paulo@0
|
475 const int h = 8;
|
paulo@0
|
476 int drawnY = v->smoothGravity ? ljfixfloor(h * p->y) : h * y;
|
paulo@0
|
477 const int color = (p->state == LJS_LANDED)
|
paulo@0
|
478 ? -128 - ((p->stateTime + 1) * 128 / (p->speed.lockDelay + 1))
|
paulo@0
|
479 : pieceColors[piece];
|
paulo@0
|
480
|
paulo@0
|
481 bits = drawPiece(v, NULL, piece,
|
paulo@0
|
482 w * (p->x + DS_PFLEFT),
|
paulo@0
|
483 h * (LJ_PF_VIS_HT + DS_PFTOP) - drawnY,
|
paulo@0
|
484 p->theta,
|
paulo@0
|
485 color, w, h);
|
paulo@0
|
486 bits = (y >= 0) ? bits << y : bits >> -y;
|
paulo@0
|
487 bits &= (1 << LJ_PF_VIS_HT) - 1;
|
paulo@0
|
488
|
paulo@0
|
489 v->backDirty |= bits | (bits << 1);
|
paulo@0
|
490 v->frontDirty |= bits | (bits << 1);
|
paulo@0
|
491 }
|
paulo@0
|
492
|
paulo@0
|
493 #define SHADOW_BLOCK 0x00
|
paulo@0
|
494
|
paulo@0
|
495 void drawShadow(LJView *v) {
|
paulo@0
|
496 LJBits bits = 0;
|
paulo@0
|
497 const LJField *const p = v->field;
|
paulo@0
|
498 int piece = p->curPiece[0];
|
paulo@0
|
499 int y = p->hardDropY;
|
paulo@0
|
500 const int w = 8;
|
paulo@0
|
501 const int h = 8;
|
paulo@0
|
502
|
paulo@0
|
503 bits = drawPiece(v, NULL, piece,
|
paulo@0
|
504 w * (p->x + DS_PFLEFT),
|
paulo@0
|
505 h * (LJ_PF_VIS_HT + DS_PFTOP - y),
|
paulo@0
|
506 p->theta,
|
paulo@0
|
507 SHADOW_BLOCK, w, h);
|
paulo@0
|
508 bits = (y >= 0) ? bits << y : bits >> -y;
|
paulo@0
|
509 bits &= (1 << LJ_PF_VIS_HT) - 1;
|
paulo@0
|
510
|
paulo@0
|
511 v->backDirty |= bits;
|
paulo@0
|
512 v->frontDirty |= bits;
|
paulo@0
|
513 }
|
paulo@0
|
514
|
paulo@0
|
515 void drawNextPieces(LJView *v) {
|
paulo@0
|
516 int holdPieceColor = v->field->alreadyHeld
|
paulo@0
|
517 ? 0x80
|
paulo@0
|
518 : pieceColors[v->field->holdPiece];
|
paulo@0
|
519
|
paulo@0
|
520 // Draw hold piece
|
paulo@0
|
521 drawPiece(v, NULL,
|
paulo@0
|
522 v->field->holdPiece,
|
paulo@0
|
523 (DS_PFLEFT - 5) * 8, (DS_PFTOP + 5) * 8, 4,
|
paulo@0
|
524 holdPieceColor, 8, 8);
|
paulo@0
|
525
|
paulo@0
|
526 // Draw next pieces
|
paulo@0
|
527 int y = 32 + 8 * DS_PFTOP;
|
paulo@0
|
528 int x = (DS_PFLEFT + LJ_PF_WID) * 8;
|
paulo@0
|
529 for(int i = 1; i <= v->nextPieces; ++i) {
|
paulo@0
|
530 int piece = v->field->curPiece[i];
|
paulo@0
|
531
|
paulo@0
|
532 if (!v->hideNext) {
|
paulo@0
|
533 drawPiece(v, NULL,
|
paulo@0
|
534 piece, x, y, 4,
|
paulo@0
|
535 pieceColors[piece], 8, 8);
|
paulo@0
|
536 }
|
paulo@0
|
537 y += 20;
|
paulo@0
|
538 }
|
paulo@0
|
539 v->frontDirty &= (1 << LJ_PF_VIS_HT) - 1;
|
paulo@0
|
540 }
|
paulo@0
|
541
|
paulo@0
|
542 void drawScore(LJView *v) {
|
paulo@0
|
543 char txt[16];
|
paulo@0
|
544 int tpm = -1;
|
paulo@0
|
545 int lvl = v->field->speedState.level;
|
paulo@0
|
546
|
paulo@0
|
547 siprintf(txt, "%8u", v->field->score);
|
paulo@0
|
548 textout(txt, 0, 7 + DS_PFTOP, 0);
|
paulo@0
|
549 siprintf(txt, "%8u", v->field->lines);
|
paulo@0
|
550 textout(txt, 0, 9 + DS_PFTOP, 0);
|
paulo@0
|
551
|
paulo@0
|
552 if (lvl > 0) {
|
paulo@0
|
553 textout("Level:", 1, SCREEN_H - 3, 0);
|
paulo@0
|
554 siprintf(txt, "%9u", lvl);
|
paulo@0
|
555 textout(txt, 0, SCREEN_H - 2, 0);
|
paulo@0
|
556 }
|
paulo@0
|
557
|
paulo@0
|
558 if (v->nLockTimes >= 2) {
|
paulo@0
|
559 int time = v->lockTime[0] - v->lockTime[v->nLockTimes - 1];
|
paulo@0
|
560 if (time > 0) {
|
paulo@0
|
561 tpm = 3600 * (v->nLockTimes - 1) / time;
|
paulo@0
|
562 }
|
paulo@0
|
563 }
|
paulo@0
|
564 if (tpm > 0) {
|
paulo@0
|
565 siprintf(txt, "%8d", tpm);
|
paulo@0
|
566 textout(txt, 0, 11 + DS_PFTOP, 0);
|
paulo@0
|
567 } else {
|
paulo@0
|
568 textout(" ---", 0, 11 + DS_PFTOP, 0);
|
paulo@0
|
569 }
|
paulo@0
|
570
|
paulo@0
|
571 {
|
paulo@0
|
572 int seconds = v->field->gameTime / 60;
|
paulo@0
|
573 int minutes = seconds / 60;
|
paulo@0
|
574 seconds -= minutes * 60;
|
paulo@0
|
575 siprintf(txt, "%6d:%02d", minutes, seconds);
|
paulo@0
|
576 textout(txt, 0, SCREEN_H - 1, 0);
|
paulo@0
|
577 }
|
paulo@0
|
578 drawNextPieces(v);
|
paulo@0
|
579 }
|