OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [MW_0_8_9PRE7/] [mw/] [src/] [demos/] [nanox/] [ntetris.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 673 markom
/*
2
 * The contents of this file are subject to the Mozilla Public License
3
 * Version 1.1 (the "License"); you may not use this file except in
4
 * compliance with the License. You may obtain a copy of the License at
5
 * http://www.mozilla.org/MPL/
6
 *
7
 * Software distributed under the License is distributed on an "AS IS"
8
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
9
 * License for the specific language governing rights and limitations
10
 * under the License.
11
 *
12
 * The Original Code is NanoTetris.
13
 *
14
 * The Initial Developer of the Original Code is Alex Holden.
15
 * Portions created by Alex Holden are Copyright (C) 2000
16
 * Alex Holden <alex@linuxhacker.org>. All Rights Reserved.
17
 *
18
 * Contributor(s):
19
 *
20
 * Alternatively, the contents of this file may be used under the terms
21
 * of the GNU General Public license (the  "[GNU] License"), in which case the
22
 * provisions of [GNU] License are applicable instead of those
23
 * above.  If you wish to allow use of your version of this file only
24
 * under the terms of the [GNU] License and not to allow others to use
25
 * your version of this file under the MPL, indicate your decision by
26
 * deleting  the provisions above and replace  them with the notice and
27
 * other provisions required by the [GNU] License.  If you do not delete
28
 * the provisions above, a recipient may use your version of this file
29
 * under either the MPL or the [GNU] License.
30
 */
31
 
32
/*
33
 * A Nano-X Tetris clone by Alex Holden.
34
 *
35
 * The objective is to keep placing new pieces for as long as possible. When a
36
 * horizontal line is filled with blocks, it will vanish, and everything above
37
 * it will drop down a line. It quickly gets difficult because the speed
38
 * increases with the score. Unlike with some Tetris clones, no bonus points
39
 * are awarded for matching colours, completing more than one line at a time,
40
 * or for using the "drop shape to bottom" function.
41
 *
42
 * The box in the top left of the game window is the score box. The top score
43
 * is the highest score you have achieved since last resetting the high score
44
 * counter. The counter is stored when the game exits in the file specified by
45
 * the HISCORE_FILE parameter ("/usr/games/nanotetris.hiscore" by default).
46
 * Note that no attempt is made to encrypt the file, so anybody with write
47
 * access to the file can alter the contents of it using a text editor.
48
 *
49
 * The box below the score box is the next shape box. This contains a "preview"
50
 * of the next shape to appear, so that you can plan ahead as you are building
51
 * up the blocks.
52
 *
53
 * The game functions can be controlled using either the mouse (or a touch pad,
54
 * touch screen, trackball, etc.) and the buttons below the next shape box, or
55
 * with the following keyboard keys:
56
 *
57
 *   Q = quit game
58
 *   N = new game
59
 *   P = pause game
60
 *   C = continue game
61
 *   D = rotate shape anticlockwise
62
 *   F = rotate shape clockwise
63
 *   J = move shape left
64
 *   K = move shape right
65
 *   Space Bar = drop shape to bottom.
66
 *
67
 * The reason for the unconventional use of D, F, J, and K keys is that they
68
 * are all in the "home" position of a QWERTY keyboard, which makes them very
69
 * easy to press if you are used to touch typing.
70
 *
71
 * I'll leave it to you to figure out which mouse operated movement button does
72
 * what (it's pretty obvious).
73
 */
74
 
75
#include <stdio.h>
76
#include <stdlib.h>
77
#include <fcntl.h>
78
#include <unistd.h>
79
#include <time.h>
80
#include <ctype.h>
81
#include <errno.h>
82
#include <sys/time.h>
83
 
84
#ifdef __ECOS
85
#define random  rand
86
#define srandom srand
87
#endif
88
 
89
#define MWINCLUDECOLORS
90
#include <nano-X.h>
91
 
92
#include "ntetris.h"
93
 
94
void *my_malloc(size_t size)
95
{
96
        void *ret;
97
 
98
        if(!(ret = malloc(size))) {
99
                fprintf(stderr, "Out of memory\n");
100
                exit(1);
101
        }
102
 
103
        return ret;
104
}
105
 
106
#ifdef HAVE_USLEEP
107
void msleep(long ms)
108
{
109
        usleep(ms * 1000);
110
}
111
#else
112
void msleep(long ms)
113
{
114
        struct timespec req, rem;
115
 
116
        req.tv_sec = ms / 1000000;
117
        req.tv_nsec = (ms % 1000000) * 1000000;
118
 
119
        while(nanosleep(&req, &rem) == -1) {
120
                if(errno == EINTR) {
121
                        req.tv_sec = rem.tv_sec;
122
                        req.tv_nsec = rem.tv_nsec;
123
                        continue;
124
                } else {
125
                        perror("nanosleep() failed");
126
                        return;
127
                }
128
        }
129
}
130
#endif
131
 
132
#ifdef USE_HISCORE_FILE
133
void read_hiscore(nstate *state)
134
{
135
        FILE *f;
136
        int i, n;
137
 
138
        if(!(f = fopen(HISCORE_FILE, "r"))) {
139
                if(errno != ENOENT)
140
                        perror("Couldn't open high score file for reading");
141
                state->hiscore = state->fhiscore = 0;
142
                return;
143
        }
144
 
145
        i = fscanf(f, "%d", &n);
146
        fclose(f);
147
 
148
        if(i != 1) {
149
                fprintf(stderr, "Couldn't read high score file\n");
150
                n = 0;
151
        }
152
 
153
        state->hiscore = state->fhiscore = n;
154
}
155
 
156
void write_hiscore(nstate *state)
157
{
158
        FILE *f;
159
 
160
        if(state->score > state->hiscore) state->hiscore = state->score;
161
        if(state->hiscore <= state->fhiscore) return;
162
 
163
        if(!(f = fopen(HISCORE_FILE, "w"))) {
164
                perror("Couldn't open high score file for writing");
165
                return;
166
        }
167
 
168
        if((fprintf(f, "%d", state->hiscore)) == -1) {
169
                perror("Couldn't write to high score file");
170
        }
171
 
172
        fclose(f);
173
}
174
#else
175
void read_hiscore(nstate *state)
176
{
177
        state->hiscore = 0;
178
}
179
 
180
void write_hiscore(nstate *state) {}
181
#endif
182
 
183
int will_collide(nstate *state, int x, int y, int orientation)
184
{
185
        int r, c, xx, yy;
186
        char ch = 0;
187
 
188
        draw_shape(state, state->current_shape.x, state->current_shape.y, 1);
189
        for(r = 0; ch < 3; r++) {
190
                ch = 0;
191
                for(c = 0; ch < 2; c++) {
192
                        ch = shapes[state->current_shape.type]
193
                                [orientation][r][c];
194
                        if(ch == 1) {
195
                                yy = y + r;
196
                                xx = x + c;
197
                                if((yy == WELL_HEIGHT) || (xx == WELL_WIDTH) ||
198
                                                (state->blocks[0][yy][xx])) {
199
                                        draw_shape(state,
200
                                                state->current_shape.x,
201
                                                state->current_shape.y, 0);
202
                                        return 1;
203
                                }
204
                        }
205
                }
206
        }
207
        draw_shape(state, state->current_shape.x, state->current_shape.y, 0);
208
 
209
        return 0;
210
}
211
 
212
void draw_shape(nstate *state, GR_COORD x, GR_COORD y, int erase)
213
{
214
        int r, c, yy, xx;
215
        GR_COLOR col;
216
        char ch = 0;
217
 
218
        if(erase) col = 0;
219
        else col = state->current_shape.colour;
220
 
221
        for(r = 0; ch < 3; r++) {
222
                ch = 0;
223
                for(c = 0; ch < 2; c++) {
224
                        ch = shapes[state->current_shape.type]
225
                                [state->current_shape.orientation][r][c];
226
                        if(ch == 1) {
227
                                yy = y + r;
228
                                xx = x + c;
229
                                state->blocks[0][yy][xx] = col;
230
                        }
231
                }
232
        }
233
}
234
 
235
void draw_well(nstate *state, int forcedraw)
236
{
237
        int x, y;
238
 
239
        for(y = WELL_NOTVISIBLE; y < WELL_HEIGHT; y++) {
240
                for(x = 0; x < WELL_WIDTH; x++) {
241
                        if(forcedraw || (state->blocks[0][y][x] !=
242
                                                state->blocks[1][y][x])) {
243
                                state->blocks[1][y][x] = state->blocks[0][y][x];
244
                                GrSetGCForeground(state->wellgc,
245
                                                        state->blocks[0][y][x]);
246
                                GrFillRect(state->well_window, state->wellgc,
247
                                        (BLOCK_SIZE * x),
248
                                        (BLOCK_SIZE * (y - WELL_NOTVISIBLE)),
249
                                                BLOCK_SIZE, BLOCK_SIZE);
250
                        }
251
                }
252
        }
253
 
254
        GrFlush();
255
}
256
 
257
void draw_score(nstate *state)
258
{
259
        char buf[32];
260
 
261
        GrFillRect(state->score_window, state->scoregcb, 0, 0,
262
                        SCORE_WINDOW_WIDTH, SCORE_WINDOW_HEIGHT);
263
 
264
        sprintf(buf, "%d", state->score);
265
        GrText(state->score_window, state->scoregcf, TEXT_X_POSITION,
266
                                        TEXT2_Y_POSITION, buf, strlen(buf), 0);
267
        sprintf(buf, "%d", state->hiscore);
268
        GrText(state->score_window, state->scoregcf, TEXT_X_POSITION,
269
                                        TEXT_Y_POSITION, buf, strlen(buf), 0);
270
}
271
 
272
void draw_next_shape(nstate *state)
273
{
274
        int r, c, startx, starty, x, y;
275
        char ch = 0;
276
 
277
        GrFillRect(state->next_shape_window, state->nextshapegcb, 0, 0,
278
                        NEXT_SHAPE_WINDOW_WIDTH, NEXT_SHAPE_WINDOW_HEIGHT);
279
 
280
        GrSetGCForeground(state->nextshapegcf, state->next_shape.colour);
281
 
282
        startx = (BLOCK_SIZE * ((NEXT_SHAPE_WINDOW_SIZE / 2) -
283
                        (shape_sizes[state->next_shape.type]
284
                        [state->next_shape.orientation][0] / 2)));
285
        starty = (BLOCK_SIZE * ((NEXT_SHAPE_WINDOW_SIZE / 2) -
286
                        (shape_sizes[state->next_shape.type]
287
                        [state->next_shape.orientation][1] / 2)));
288
 
289
        for(r = 0; ch < 3; r++) {
290
                ch = 0;
291
                for(c = 0; ch < 2; c++) {
292
                        ch = shapes[state->next_shape.type]
293
                                [state->next_shape.orientation][r][c];
294
                        if(ch == 1) {
295
                                x = startx + (c * BLOCK_SIZE);
296
                                y = starty + (r * BLOCK_SIZE);
297
                                GrFillRect(state->next_shape_window,
298
                                        state->nextshapegcf, x, y,
299
                                        BLOCK_SIZE, BLOCK_SIZE);
300
                        }
301
                }
302
        }
303
}
304
 
305
void draw_new_game_button(nstate *state)
306
{
307
        GrFillRect(state->new_game_button, state->buttongcb, 0, 0,
308
                        NEW_GAME_BUTTON_WIDTH, NEW_GAME_BUTTON_HEIGHT);
309
        GrText(state->new_game_button, state->buttongcf, TEXT_X_POSITION,
310
                                        TEXT_Y_POSITION, "New Game", 8, 0);
311
}
312
 
313
void draw_anticlockwise_button(nstate *state)
314
{
315
        if(!state->running_buttons_mapped) return;
316
        GrFillRect(state->anticlockwise_button, state->buttongcb, 0, 0,
317
                ANTICLOCKWISE_BUTTON_WIDTH, ANTICLOCKWISE_BUTTON_HEIGHT);
318
        GrText(state->anticlockwise_button, state->buttongcf, TEXT_X_POSITION,
319
                                        TEXT_Y_POSITION, "   /", 4, 0);
320
}
321
 
322
void draw_clockwise_button(nstate *state)
323
{
324
        if(!state->running_buttons_mapped) return;
325
        GrFillRect(state->clockwise_button, state->buttongcb, 0, 0,
326
                        CLOCKWISE_BUTTON_WIDTH, CLOCKWISE_BUTTON_HEIGHT);
327
        GrText(state->clockwise_button, state->buttongcf, TEXT_X_POSITION,
328
                                        TEXT_Y_POSITION, "   \\", 4, 0);
329
}
330
 
331
void draw_left_button(nstate *state)
332
{
333
        if(!state->running_buttons_mapped) return;
334
        GrFillRect(state->left_button, state->buttongcb, 0, 0,
335
                        LEFT_BUTTON_WIDTH, LEFT_BUTTON_HEIGHT);
336
        GrText(state->left_button, state->buttongcf, TEXT_X_POSITION,
337
                                        TEXT_Y_POSITION, "  <", 3, 0);
338
}
339
 
340
void draw_right_button(nstate *state)
341
{
342
        if(!state->running_buttons_mapped) return;
343
        GrFillRect(state->right_button, state->buttongcb, 0, 0,
344
                        RIGHT_BUTTON_WIDTH, RIGHT_BUTTON_HEIGHT);
345
        GrText(state->right_button, state->buttongcf, TEXT_X_POSITION,
346
                                        TEXT_Y_POSITION, "   >", 4, 0);
347
}
348
 
349
void draw_drop_button(nstate *state)
350
{
351
        if(!state->running_buttons_mapped) return;
352
        GrFillRect(state->drop_button, state->buttongcb, 0, 0,
353
                        DROP_BUTTON_WIDTH, DROP_BUTTON_HEIGHT);
354
        GrText(state->drop_button, state->buttongcf, TEXT_X_POSITION,
355
                                        TEXT_Y_POSITION, "    Drop", 8, 0);
356
}
357
 
358
void draw_pause_continue_button(nstate *state)
359
{
360
        if((state->running_buttons_mapped) && (state->state == STATE_STOPPED)) {
361
                GrUnmapWindow(state->pause_continue_button);
362
                GrUnmapWindow(state->anticlockwise_button);
363
                GrUnmapWindow(state->clockwise_button);
364
                GrUnmapWindow(state->left_button);
365
                GrUnmapWindow(state->right_button);
366
                GrUnmapWindow(state->drop_button);
367
                state->running_buttons_mapped = 0;
368
                return;
369
        }
370
        if((!state->running_buttons_mapped) && (state->state == STATE_RUNNING)){
371
                GrMapWindow(state->pause_continue_button);
372
                GrMapWindow(state->anticlockwise_button);
373
                GrMapWindow(state->clockwise_button);
374
                GrMapWindow(state->left_button);
375
                GrMapWindow(state->right_button);
376
                GrMapWindow(state->drop_button);
377
                state->running_buttons_mapped = 1;
378
                return;
379
        }
380
        if(!state->running_buttons_mapped) return;
381
        GrFillRect(state->pause_continue_button, state->buttongcb, 0, 0,
382
                PAUSE_CONTINUE_BUTTON_WIDTH, PAUSE_CONTINUE_BUTTON_HEIGHT);
383
        if(state->state == STATE_PAUSED) {
384
                GrText(state->pause_continue_button, state->buttongcf,
385
                        TEXT_X_POSITION, TEXT_Y_POSITION, " Continue", 9, 0);
386
        } else {
387
                GrText(state->pause_continue_button, state->buttongcf,
388
                        TEXT_X_POSITION, TEXT_Y_POSITION, "   Pause", 8, 0);
389
        }
390
}
391
 
392
int block_is_all_in_well(nstate *state)
393
{
394
        if(state->current_shape.y >= WELL_NOTVISIBLE)
395
                return 1;
396
 
397
        return 0;
398
}
399
 
400
void delete_line(nstate *state, int line)
401
{
402
        int x, y;
403
 
404
        if(line < WELL_NOTVISIBLE) return;
405
 
406
        for(y = line - 1; y; y--)
407
                for(x = WELL_WIDTH; x; x--)
408
                        state->blocks[0][y + 1][x] = state->blocks[0][y][x];
409
 
410
        draw_well(state, 0);
411
}
412
 
413
void block_reached_bottom(nstate *state)
414
{
415
        int x, y;
416
 
417
        if(!block_is_all_in_well(state)) {
418
                state->state = STATE_STOPPED;
419
                return;
420
        }
421
 
422
        for(y = WELL_HEIGHT - 1; y; y--) {
423
                for(x = 0; x < WELL_WIDTH; x++)
424
                        if(!state->blocks[0][y][x]) goto nr;
425
                msleep(DELETE_LINE_DELAY);
426
                delete_line(state, y);
427
                state->score += SCORE_INCREMENT;
428
                if((LEVELS > (state->level + 1)) && (((state->level + 1) *
429
                                        LEVEL_DIVISOR) <= state->score))
430
                        state->level++;
431
                draw_score(state);
432
                y++;
433
                nr:
434
        }
435
 
436
        choose_new_shape(state);
437
        draw_next_shape(state);
438
}
439
 
440
void move_block(nstate *state, int direction)
441
{
442
        if(direction == 0) {
443
                if(!state->current_shape.x) return;
444
                else {
445
                        if(!will_collide(state, (state->current_shape.x - 1),
446
                                                state->current_shape.y,
447
                                        state->current_shape.orientation)) {
448
                                draw_shape(state, state->current_shape.x,
449
                                                state->current_shape.y, 1);
450
                                state->current_shape.x--;
451
                                draw_shape(state, state->current_shape.x,
452
                                                state->current_shape.y, 0);
453
                                draw_well(state, 0);
454
                        }
455
                }
456
        } else {
457
                if(!will_collide(state, (state->current_shape.x + 1),
458
                                                state->current_shape.y,
459
                                        state->current_shape.orientation)) {
460
                        draw_shape(state, state->current_shape.x,
461
                                        state->current_shape.y, 1);
462
                        state->current_shape.x++;
463
                        draw_shape(state, state->current_shape.x,
464
                                        state->current_shape.y, 0);
465
                        draw_well(state, 0);
466
                }
467
        }
468
}
469
 
470
void rotate_block(nstate *state, int direction)
471
{
472
        int neworientation = 0;
473
 
474
        if(direction == 0) {
475
                if(!state->current_shape.orientation)
476
                        neworientation = MAXORIENTATIONS - 1;
477
                else neworientation = state->current_shape.orientation - 1;
478
        } else {
479
                neworientation = state->current_shape.orientation + 1;
480
                if(neworientation == MAXORIENTATIONS) neworientation = 0;
481
        }
482
 
483
        if(!will_collide(state, state->current_shape.x, state->current_shape.y,
484
                                                        neworientation)) {
485
                draw_shape(state, state->current_shape.x,
486
                                state->current_shape.y, 1);
487
                state->current_shape.orientation = neworientation;
488
                draw_shape(state, state->current_shape.x,
489
                                state->current_shape.y, 0);
490
                draw_well(state, 0);
491
        }
492
}
493
 
494
int drop_block_1(nstate *state)
495
{
496
        if(will_collide(state, state->current_shape.x,
497
                                (state->current_shape.y + 1),
498
                                state->current_shape.orientation)) {
499
                block_reached_bottom(state);
500
                return 1;
501
        }
502
 
503
        draw_shape(state, state->current_shape.x, state->current_shape.y, 1);
504
        state->current_shape.y++;
505
        draw_shape(state, state->current_shape.x, state->current_shape.y, 0);
506
 
507
        draw_well(state, 0);
508
 
509
        return 0;
510
}
511
 
512
void drop_block(nstate *state)
513
{
514
        while(!drop_block_1(state)) msleep(DROP_BLOCK_DELAY);
515
}
516
 
517
void handle_exposure_event(nstate *state)
518
{
519
        GR_EVENT_EXPOSURE *event = &state->event.exposure;
520
 
521
        if(event->wid == state->score_window) {
522
                draw_score(state);
523
                return;
524
        }
525
        if(event->wid == state->next_shape_window) {
526
                draw_next_shape(state);
527
                return;
528
        }
529
        if(event->wid == state->new_game_button) {
530
                draw_new_game_button(state);
531
                return;
532
        }
533
        if(event->wid == state->pause_continue_button) {
534
                draw_pause_continue_button(state);
535
                return;
536
        }
537
        if(event->wid == state->anticlockwise_button) {
538
                draw_anticlockwise_button(state);
539
                return;
540
        }
541
        if(event->wid == state->clockwise_button) {
542
                draw_clockwise_button(state);
543
                return;
544
        }
545
        if(event->wid == state->left_button) {
546
                draw_left_button(state);
547
                return;
548
        }
549
        if(event->wid == state->right_button) {
550
                draw_right_button(state);
551
                return;
552
        }
553
        if(event->wid == state->drop_button) {
554
                draw_drop_button(state);
555
                return;
556
        }
557
        if(event->wid == state->well_window) {
558
                draw_well(state, 1);
559
                return;
560
        }
561
}
562
 
563
void handle_mouse_event(nstate *state)
564
{
565
        GR_EVENT_MOUSE *event = &state->event.mouse;
566
 
567
        if(event->wid == state->new_game_button) {
568
                state->state = STATE_NEWGAME;
569
                return;
570
        }
571
        if(event->wid == state->pause_continue_button) {
572
                if(state->state == STATE_PAUSED) state->state = STATE_RUNNING;
573
                else state->state = STATE_PAUSED;
574
                return;
575
        }
576
        if(event->wid == state->anticlockwise_button) {
577
                if(state->state == STATE_PAUSED) state->state = STATE_RUNNING;
578
                rotate_block(state, 0);
579
                return;
580
        }
581
        if(event->wid == state->clockwise_button) {
582
                if(state->state == STATE_PAUSED) state->state = STATE_RUNNING;
583
                rotate_block(state, 1);
584
                return;
585
        }
586
        if(event->wid == state->left_button) {
587
                if(state->state == STATE_PAUSED) state->state = STATE_RUNNING;
588
                move_block(state, 0);
589
                return;
590
        }
591
        if(event->wid == state->right_button) {
592
                if(state->state == STATE_PAUSED) state->state = STATE_RUNNING;
593
                move_block(state, 1);
594
                return;
595
        }
596
        if(event->wid == state->drop_button) {
597
                if(state->state == STATE_PAUSED) state->state = STATE_RUNNING;
598
                drop_block(state);
599
                return;
600
        }
601
}
602
 
603
void handle_keyboard_event(nstate *state)
604
{
605
        GR_EVENT_KEYSTROKE *event = &state->event.keystroke;
606
 
607
        switch(event->ch) {
608
                case 'q':
609
                case 'Q':
610
                case MWKEY_CANCEL:
611
                        state->state = STATE_EXIT;
612
                        return;
613
                case 'n':
614
                case 'N':
615
                case MWKEY_APP1:
616
                        state->state = STATE_NEWGAME;
617
                        return;
618
        }
619
 
620
        if(state->state == STATE_STOPPED) return;
621
 
622
        state->state = STATE_RUNNING;
623
 
624
        switch(event->ch) {
625
                case 'p':
626
                case 'P':
627
                        state->state = STATE_PAUSED;
628
                        break;
629
                case 'j':
630
                case 'J':
631
                case MWKEY_LEFT:
632
                        move_block(state, 0);
633
                        break;
634
                case 'k':
635
                case 'K':
636
                case MWKEY_RIGHT:
637
                        move_block(state, 1);
638
                        break;
639
                case 'd':
640
                case 'D':
641
                case MWKEY_UP:
642
                        rotate_block(state, 0);
643
                        break;
644
                case 'f':
645
                case 'F':
646
                case MWKEY_DOWN:
647
                        rotate_block(state, 1);
648
                        break;
649
                case ' ':
650
                case MWKEY_MENU:
651
                        drop_block(state);
652
                        break;
653
        }
654
}
655
 
656
void handle_event(nstate *state)
657
{
658
        switch(state->event.type) {
659
                case GR_EVENT_TYPE_EXPOSURE:
660
                        handle_exposure_event(state);
661
                        break;
662
                case GR_EVENT_TYPE_BUTTON_DOWN:
663
                        handle_mouse_event(state);
664
                        break;
665
                case GR_EVENT_TYPE_KEY_DOWN:
666
                        handle_keyboard_event(state);
667
                        break;
668
                case GR_EVENT_TYPE_CLOSE_REQ:
669
                        state->state = STATE_EXIT;
670
                        break;
671
                case GR_EVENT_TYPE_TIMEOUT:
672
                        break;
673
                default:
674
                        fprintf(stderr, "Unhandled event type %d\n",
675
                                                        state->event.type);
676
                        break;
677
        }
678
}
679
 
680
void clear_well(nstate *state)
681
{
682
        int x, y;
683
 
684
        for(y = 0; y < WELL_HEIGHT; y++)
685
                for(x = 0; x < WELL_WIDTH; x++) {
686
                        state->blocks[0][y][x] = 0;
687
                        state->blocks[1][y][x] = 0;
688
                }
689
}
690
 
691
/* Dirty hack alert- this is to avoid using any floating point math */
692
int random8(int limit)
693
{
694
        int ret;
695
 
696
        do { ret = random() & 7; } while(ret > limit);
697
 
698
        return ret;
699
}
700
 
701
void choose_new_shape(nstate *state)
702
{
703
        state->current_shape.type = state->next_shape.type;
704
        state->current_shape.orientation = state->next_shape.orientation;
705
        state->current_shape.colour = state->next_shape.colour;
706
        state->current_shape.x = (WELL_WIDTH / 2) - 2;
707
        state->current_shape.y = WELL_NOTVISIBLE -
708
                        shape_sizes[state->next_shape.type]
709
                                [state->next_shape.orientation][1] - 1;
710
        state->next_shape.type = random8(MAXSHAPES - 1);
711
        state->next_shape.orientation = random8(MAXORIENTATIONS - 1);
712
        state->next_shape.colour = block_colours[random8(MAX_BLOCK_COLOUR)];
713
}
714
 
715
void new_game(nstate *state)
716
{
717
        clear_well(state);
718
        if(state->score > state->hiscore) state->hiscore = state->score;
719
        state->score = 0;
720
        state->level = 0;
721
        draw_score(state);
722
        choose_new_shape(state);
723
        draw_next_shape(state);
724
        draw_well(state, 1);
725
        if(state->state == STATE_NEWGAME) state->state = STATE_RUNNING;
726
}
727
 
728
void init_game(nstate *state)
729
{
730
        GR_WM_PROPERTIES props;
731
 
732
        if(GrOpen() < 0) {
733
                fprintf(stderr, "Couldn't connect to Nano-X server\n");
734
                exit(1);
735
        }
736
 
737
        state->main_window = GrNewWindow(GR_ROOT_WINDOW_ID,
738
                                        MAIN_WINDOW_X_POSITION,
739
                                        MAIN_WINDOW_Y_POSITION,
740
                                        MAIN_WINDOW_WIDTH,
741
                                        MAIN_WINDOW_HEIGHT, 0,
742
                                        MAIN_WINDOW_BACKGROUND_COLOUR, 0);
743
        /* set title */
744
        props.flags = GR_WM_FLAGS_TITLE | GR_WM_FLAGS_PROPS;
745
        props.props = GR_WM_PROPS_BORDER | GR_WM_PROPS_CAPTION;
746
        props.title = "Nano-Tetris";
747
        GrSetWMProperties(state->main_window, &props);
748
        GrSelectEvents(state->main_window, GR_EVENT_MASK_EXPOSURE |
749
                                        GR_EVENT_MASK_CLOSE_REQ |
750
                                        GR_EVENT_MASK_KEY_DOWN |
751
                                        GR_EVENT_MASK_TIMEOUT);
752
 
753
        state->score_window = GrNewWindow(state->main_window,
754
                                        SCORE_WINDOW_X_POSITION,
755
                                        SCORE_WINDOW_Y_POSITION,
756
                                        SCORE_WINDOW_WIDTH,
757
                                        SCORE_WINDOW_HEIGHT, 0,
758
                                        SCORE_WINDOW_BACKGROUND_COLOUR, 0);
759
        GrSelectEvents(state->score_window, GR_EVENT_MASK_EXPOSURE);
760
        GrMapWindow(state->score_window);
761
        state->scoregcf = GrNewGC();
762
        GrSetGCForeground(state->scoregcf, SCORE_WINDOW_FOREGROUND_COLOUR);
763
        GrSetGCBackground(state->scoregcf, SCORE_WINDOW_BACKGROUND_COLOUR);
764
        state->scoregcb = GrNewGC();
765
        GrSetGCForeground(state->scoregcb, SCORE_WINDOW_BACKGROUND_COLOUR);
766
 
767
        state->next_shape_window = GrNewWindow(state->main_window,
768
                                        NEXT_SHAPE_WINDOW_X_POSITION,
769
                                        NEXT_SHAPE_WINDOW_Y_POSITION,
770
                                        NEXT_SHAPE_WINDOW_WIDTH,
771
                                        NEXT_SHAPE_WINDOW_HEIGHT, 0,
772
                                        NEXT_SHAPE_WINDOW_BACKGROUND_COLOUR, 0);
773
        GrSelectEvents(state->next_shape_window, GR_EVENT_MASK_EXPOSURE);
774
        GrMapWindow(state->next_shape_window);
775
        state->nextshapegcf = GrNewGC();
776
        state->nextshapegcb = GrNewGC();
777
        GrSetGCForeground(state->nextshapegcb,
778
                                NEXT_SHAPE_WINDOW_BACKGROUND_COLOUR);
779
 
780
        state->new_game_button = GrNewWindow(state->main_window,
781
                                        NEW_GAME_BUTTON_X_POSITION,
782
                                        NEW_GAME_BUTTON_Y_POSITION,
783
                                        NEW_GAME_BUTTON_WIDTH,
784
                                        NEW_GAME_BUTTON_HEIGHT, 0,
785
                                        BUTTON_BACKGROUND_COLOUR, 0);
786
        GrSelectEvents(state->new_game_button, GR_EVENT_MASK_EXPOSURE |
787
                                        GR_EVENT_MASK_BUTTON_DOWN);
788
        GrMapWindow(state->new_game_button);
789
        state->buttongcf = GrNewGC();
790
        GrSetGCForeground(state->buttongcf, BUTTON_FOREGROUND_COLOUR);
791
        GrSetGCBackground(state->buttongcf, BUTTON_BACKGROUND_COLOUR);
792
        state->buttongcb = GrNewGC();
793
        GrSetGCForeground(state->buttongcb, BUTTON_BACKGROUND_COLOUR);
794
 
795
        state->pause_continue_button = GrNewWindow(state->main_window,
796
                                        PAUSE_CONTINUE_BUTTON_X_POSITION,
797
                                        PAUSE_CONTINUE_BUTTON_Y_POSITION,
798
                                        PAUSE_CONTINUE_BUTTON_WIDTH,
799
                                        PAUSE_CONTINUE_BUTTON_HEIGHT, 0,
800
                                        BUTTON_BACKGROUND_COLOUR, 0);
801
        GrSelectEvents(state->pause_continue_button, GR_EVENT_MASK_EXPOSURE |
802
                                        GR_EVENT_MASK_BUTTON_DOWN);
803
 
804
        state->anticlockwise_button = GrNewWindow(state->main_window,
805
                                        ANTICLOCKWISE_BUTTON_X_POSITION,
806
                                        ANTICLOCKWISE_BUTTON_Y_POSITION,
807
                                        ANTICLOCKWISE_BUTTON_WIDTH,
808
                                        ANTICLOCKWISE_BUTTON_HEIGHT, 0,
809
                                        BUTTON_BACKGROUND_COLOUR,
810
                                        0);
811
        GrSelectEvents(state->anticlockwise_button, GR_EVENT_MASK_EXPOSURE |
812
                                        GR_EVENT_MASK_BUTTON_DOWN);
813
 
814
        state->clockwise_button = GrNewWindow(state->main_window,
815
                                        CLOCKWISE_BUTTON_X_POSITION,
816
                                        CLOCKWISE_BUTTON_Y_POSITION,
817
                                        CLOCKWISE_BUTTON_WIDTH,
818
                                        CLOCKWISE_BUTTON_HEIGHT, 0,
819
                                        BUTTON_BACKGROUND_COLOUR,
820
                                        0);
821
        GrSelectEvents(state->clockwise_button, GR_EVENT_MASK_EXPOSURE |
822
                                        GR_EVENT_MASK_BUTTON_DOWN);
823
 
824
        state->left_button = GrNewWindow(state->main_window,
825
                                        LEFT_BUTTON_X_POSITION,
826
                                        LEFT_BUTTON_Y_POSITION,
827
                                        LEFT_BUTTON_WIDTH,
828
                                        LEFT_BUTTON_HEIGHT, 0,
829
                                        BUTTON_BACKGROUND_COLOUR,
830
                                        0);
831
        GrSelectEvents(state->left_button, GR_EVENT_MASK_EXPOSURE |
832
                                        GR_EVENT_MASK_BUTTON_DOWN);
833
 
834
        state->right_button = GrNewWindow(state->main_window,
835
                                        RIGHT_BUTTON_X_POSITION,
836
                                        RIGHT_BUTTON_Y_POSITION,
837
                                        RIGHT_BUTTON_WIDTH,
838
                                        RIGHT_BUTTON_HEIGHT, 0,
839
                                        BUTTON_BACKGROUND_COLOUR,
840
                                        0);
841
        GrSelectEvents(state->right_button, GR_EVENT_MASK_EXPOSURE |
842
                                        GR_EVENT_MASK_BUTTON_DOWN);
843
 
844
        state->drop_button = GrNewWindow(state->main_window,
845
                                        DROP_BUTTON_X_POSITION,
846
                                        DROP_BUTTON_Y_POSITION,
847
                                        DROP_BUTTON_WIDTH,
848
                                        DROP_BUTTON_HEIGHT, 0,
849
                                        BUTTON_BACKGROUND_COLOUR,
850
                                        0);
851
        GrSelectEvents(state->drop_button, GR_EVENT_MASK_EXPOSURE |
852
                                        GR_EVENT_MASK_BUTTON_DOWN);
853
 
854
        state->well_window = GrNewWindow(state->main_window,
855
                                        WELL_WINDOW_X_POSITION,
856
                                        WELL_WINDOW_Y_POSITION,
857
                                        WELL_WINDOW_WIDTH,
858
                                        WELL_WINDOW_HEIGHT, 0,
859
                                        WELL_WINDOW_BACKGROUND_COLOUR, 0);
860
        GrSelectEvents(state->well_window, GR_EVENT_MASK_EXPOSURE);
861
        GrMapWindow(state->well_window);
862
        state->wellgc = GrNewGC();
863
 
864
        GrMapWindow(state->main_window);
865
 
866
        state->state = STATE_STOPPED;
867
        state->score = 0;
868
        read_hiscore(state);
869
        state->level = 0;
870
        state->running_buttons_mapped = 0;
871
 
872
        srandom(time(0));
873
 
874
        choose_new_shape(state);
875
        new_game(state);
876
}
877
 
878
void calculate_timeout(nstate *state)
879
{
880
        struct timeval t;
881
        long u;
882
 
883
        gettimeofday(&t, NULL);
884
        u = t.tv_usec + (delays[state->level] * 1000);
885
        state->timeout.tv_sec = t.tv_sec + (u / 1000000);
886
        state->timeout.tv_usec = u % 1000000;
887
}
888
 
889
unsigned long timeout_delay(nstate *state)
890
{
891
        struct timeval t;
892
        signed long s, m, ret;
893
 
894
        gettimeofday(&t, NULL);
895
 
896
        if((t.tv_sec > state->timeout.tv_sec) ||
897
                        ((t.tv_sec == state->timeout.tv_sec) &&
898
                        t.tv_usec >= state->timeout.tv_usec)) return 1;
899
 
900
        s = state->timeout.tv_sec - t.tv_sec;
901
        m = ((state->timeout.tv_usec - t.tv_usec) / 1000);
902
        ret = (unsigned long)((1000 * s) + m);
903
/*
904
        fprintf(stderr, "t.tv_sec = %ld, t.tv_usec = %ld, timeout.tv_sec = "
905
                "%ld, timeout.tv_usec = %ld, s = %ld, m = %ld, ret = %ld\n",
906
                t.tv_sec, t.tv_usec, state->timeout.tv_sec,
907
                state->timeout.tv_usec, s, m, ret);
908
*/
909
        if(ret <= 0) return 1;
910
        else return ret;
911
}
912
 
913
void do_update(nstate *state)
914
{
915
        struct timeval t;
916
 
917
        gettimeofday(&t, NULL);
918
 
919
        if((t.tv_sec > state->timeout.tv_sec) ||
920
                        ((t.tv_sec == state->timeout.tv_sec) &&
921
                        (t.tv_usec >= state->timeout.tv_usec))) {
922
                drop_block_1(state);
923
                calculate_timeout(state);
924
        }
925
}
926
 
927
void do_pause(nstate *state)
928
{
929
        draw_pause_continue_button(state);
930
        while(state->state == STATE_PAUSED) {
931
                GrGetNextEvent(&state->event);
932
                handle_event(state);
933
        }
934
        draw_pause_continue_button(state);
935
}
936
 
937
void wait_for_start(nstate *state)
938
{
939
        draw_pause_continue_button(state);
940
        while(state->state == STATE_STOPPED) {
941
                GrGetNextEvent(&state->event);
942
                handle_event(state);
943
        }
944
        if(state->state == STATE_NEWGAME) state->state = STATE_RUNNING;
945
        draw_pause_continue_button(state);
946
        calculate_timeout(state);
947
}
948
 
949
void run_game(nstate *state)
950
{
951
        while(state->state == STATE_RUNNING) {
952
                GrGetNextEventTimeout(&state->event, timeout_delay(state));
953
                handle_event(state);
954
                if(state->state == STATE_PAUSED) do_pause(state);
955
                if(state->state == STATE_RUNNING) do_update(state);
956
        }
957
}
958
 
959
void main_game_loop(nstate *state)
960
{
961
        wait_for_start(state);
962
        while(state->state != STATE_EXIT) {
963
                if(state->state == STATE_RUNNING) run_game(state);
964
                if(state->state == STATE_STOPPED) wait_for_start(state);
965
                if(state->state != STATE_EXIT) new_game(state);
966
        }
967
}
968
 
969
int main(int argc, char *argv[])
970
{
971
        nstate *state = my_malloc(sizeof(nstate));
972
 
973
        init_game(state);
974
        main_game_loop(state);
975
 
976
        write_hiscore(state);
977
 
978
        GrClose();
979
 
980
        return 0;
981
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.