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

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [mw/] [src/] [demos/] [nanox/] [ntetris.c] - Blame information for rev 716

Go to most recent revision | 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 716 simons
/* SIMON: we use strlen */
83
#include <string.h>
84 673 markom
#include <sys/time.h>
85
 
86
#ifdef __ECOS
87
#define random  rand
88
#define srandom srand
89
#endif
90
 
91
#define MWINCLUDECOLORS
92
#include <nano-X.h>
93
 
94
#include "ntetris.h"
95
 
96
void *my_malloc(size_t size)
97
{
98
        void *ret;
99
 
100
        if(!(ret = malloc(size))) {
101
                fprintf(stderr, "Out of memory\n");
102
                exit(1);
103
        }
104
 
105
        return ret;
106
}
107
 
108
#ifdef HAVE_USLEEP
109
void msleep(long ms)
110
{
111
        usleep(ms * 1000);
112
}
113
#else
114
void msleep(long ms)
115
{
116
        struct timespec req, rem;
117
 
118
        req.tv_sec = ms / 1000000;
119
        req.tv_nsec = (ms % 1000000) * 1000000;
120
 
121
        while(nanosleep(&req, &rem) == -1) {
122
                if(errno == EINTR) {
123
                        req.tv_sec = rem.tv_sec;
124
                        req.tv_nsec = rem.tv_nsec;
125
                        continue;
126
                } else {
127
                        perror("nanosleep() failed");
128
                        return;
129
                }
130
        }
131
}
132
#endif
133
 
134
#ifdef USE_HISCORE_FILE
135
void read_hiscore(nstate *state)
136
{
137
        FILE *f;
138
        int i, n;
139
 
140
        if(!(f = fopen(HISCORE_FILE, "r"))) {
141
                if(errno != ENOENT)
142
                        perror("Couldn't open high score file for reading");
143
                state->hiscore = state->fhiscore = 0;
144
                return;
145
        }
146
 
147
        i = fscanf(f, "%d", &n);
148
        fclose(f);
149
 
150
        if(i != 1) {
151
                fprintf(stderr, "Couldn't read high score file\n");
152
                n = 0;
153
        }
154
 
155
        state->hiscore = state->fhiscore = n;
156
}
157
 
158
void write_hiscore(nstate *state)
159
{
160
        FILE *f;
161
 
162
        if(state->score > state->hiscore) state->hiscore = state->score;
163
        if(state->hiscore <= state->fhiscore) return;
164
 
165
        if(!(f = fopen(HISCORE_FILE, "w"))) {
166
                perror("Couldn't open high score file for writing");
167
                return;
168
        }
169
 
170
        if((fprintf(f, "%d", state->hiscore)) == -1) {
171
                perror("Couldn't write to high score file");
172
        }
173
 
174
        fclose(f);
175
}
176
#else
177
void read_hiscore(nstate *state)
178
{
179
        state->hiscore = 0;
180
}
181
 
182
void write_hiscore(nstate *state) {}
183
#endif
184
 
185
int will_collide(nstate *state, int x, int y, int orientation)
186
{
187
        int r, c, xx, yy;
188
        char ch = 0;
189
 
190
        draw_shape(state, state->current_shape.x, state->current_shape.y, 1);
191
        for(r = 0; ch < 3; r++) {
192
                ch = 0;
193
                for(c = 0; ch < 2; c++) {
194
                        ch = shapes[state->current_shape.type]
195
                                [orientation][r][c];
196
                        if(ch == 1) {
197
                                yy = y + r;
198
                                xx = x + c;
199
                                if((yy == WELL_HEIGHT) || (xx == WELL_WIDTH) ||
200
                                                (state->blocks[0][yy][xx])) {
201
                                        draw_shape(state,
202
                                                state->current_shape.x,
203
                                                state->current_shape.y, 0);
204
                                        return 1;
205
                                }
206
                        }
207
                }
208
        }
209
        draw_shape(state, state->current_shape.x, state->current_shape.y, 0);
210
 
211
        return 0;
212
}
213
 
214
void draw_shape(nstate *state, GR_COORD x, GR_COORD y, int erase)
215
{
216
        int r, c, yy, xx;
217
        GR_COLOR col;
218
        char ch = 0;
219
 
220
        if(erase) col = 0;
221
        else col = state->current_shape.colour;
222
 
223
        for(r = 0; ch < 3; r++) {
224
                ch = 0;
225
                for(c = 0; ch < 2; c++) {
226
                        ch = shapes[state->current_shape.type]
227
                                [state->current_shape.orientation][r][c];
228
                        if(ch == 1) {
229
                                yy = y + r;
230
                                xx = x + c;
231
                                state->blocks[0][yy][xx] = col;
232
                        }
233
                }
234
        }
235
}
236
 
237
void draw_well(nstate *state, int forcedraw)
238
{
239
        int x, y;
240
 
241
        for(y = WELL_NOTVISIBLE; y < WELL_HEIGHT; y++) {
242
                for(x = 0; x < WELL_WIDTH; x++) {
243
                        if(forcedraw || (state->blocks[0][y][x] !=
244
                                                state->blocks[1][y][x])) {
245
                                state->blocks[1][y][x] = state->blocks[0][y][x];
246
                                GrSetGCForeground(state->wellgc,
247
                                                        state->blocks[0][y][x]);
248
                                GrFillRect(state->well_window, state->wellgc,
249
                                        (BLOCK_SIZE * x),
250
                                        (BLOCK_SIZE * (y - WELL_NOTVISIBLE)),
251
                                                BLOCK_SIZE, BLOCK_SIZE);
252
                        }
253
                }
254
        }
255
 
256
        GrFlush();
257
}
258
 
259
void draw_score(nstate *state)
260
{
261
        char buf[32];
262
 
263
        GrFillRect(state->score_window, state->scoregcb, 0, 0,
264
                        SCORE_WINDOW_WIDTH, SCORE_WINDOW_HEIGHT);
265
 
266
        sprintf(buf, "%d", state->score);
267
        GrText(state->score_window, state->scoregcf, TEXT_X_POSITION,
268
                                        TEXT2_Y_POSITION, buf, strlen(buf), 0);
269
        sprintf(buf, "%d", state->hiscore);
270
        GrText(state->score_window, state->scoregcf, TEXT_X_POSITION,
271
                                        TEXT_Y_POSITION, buf, strlen(buf), 0);
272
}
273
 
274
void draw_next_shape(nstate *state)
275
{
276
        int r, c, startx, starty, x, y;
277
        char ch = 0;
278
 
279
        GrFillRect(state->next_shape_window, state->nextshapegcb, 0, 0,
280
                        NEXT_SHAPE_WINDOW_WIDTH, NEXT_SHAPE_WINDOW_HEIGHT);
281
 
282
        GrSetGCForeground(state->nextshapegcf, state->next_shape.colour);
283
 
284
        startx = (BLOCK_SIZE * ((NEXT_SHAPE_WINDOW_SIZE / 2) -
285
                        (shape_sizes[state->next_shape.type]
286
                        [state->next_shape.orientation][0] / 2)));
287
        starty = (BLOCK_SIZE * ((NEXT_SHAPE_WINDOW_SIZE / 2) -
288
                        (shape_sizes[state->next_shape.type]
289
                        [state->next_shape.orientation][1] / 2)));
290
 
291
        for(r = 0; ch < 3; r++) {
292
                ch = 0;
293
                for(c = 0; ch < 2; c++) {
294
                        ch = shapes[state->next_shape.type]
295
                                [state->next_shape.orientation][r][c];
296
                        if(ch == 1) {
297
                                x = startx + (c * BLOCK_SIZE);
298
                                y = starty + (r * BLOCK_SIZE);
299
                                GrFillRect(state->next_shape_window,
300
                                        state->nextshapegcf, x, y,
301
                                        BLOCK_SIZE, BLOCK_SIZE);
302
                        }
303
                }
304
        }
305
}
306
 
307
void draw_new_game_button(nstate *state)
308
{
309
        GrFillRect(state->new_game_button, state->buttongcb, 0, 0,
310
                        NEW_GAME_BUTTON_WIDTH, NEW_GAME_BUTTON_HEIGHT);
311
        GrText(state->new_game_button, state->buttongcf, TEXT_X_POSITION,
312
                                        TEXT_Y_POSITION, "New Game", 8, 0);
313
}
314
 
315
void draw_anticlockwise_button(nstate *state)
316
{
317
        if(!state->running_buttons_mapped) return;
318
        GrFillRect(state->anticlockwise_button, state->buttongcb, 0, 0,
319
                ANTICLOCKWISE_BUTTON_WIDTH, ANTICLOCKWISE_BUTTON_HEIGHT);
320
        GrText(state->anticlockwise_button, state->buttongcf, TEXT_X_POSITION,
321
                                        TEXT_Y_POSITION, "   /", 4, 0);
322
}
323
 
324
void draw_clockwise_button(nstate *state)
325
{
326
        if(!state->running_buttons_mapped) return;
327
        GrFillRect(state->clockwise_button, state->buttongcb, 0, 0,
328
                        CLOCKWISE_BUTTON_WIDTH, CLOCKWISE_BUTTON_HEIGHT);
329
        GrText(state->clockwise_button, state->buttongcf, TEXT_X_POSITION,
330
                                        TEXT_Y_POSITION, "   \\", 4, 0);
331
}
332
 
333
void draw_left_button(nstate *state)
334
{
335
        if(!state->running_buttons_mapped) return;
336
        GrFillRect(state->left_button, state->buttongcb, 0, 0,
337
                        LEFT_BUTTON_WIDTH, LEFT_BUTTON_HEIGHT);
338
        GrText(state->left_button, state->buttongcf, TEXT_X_POSITION,
339
                                        TEXT_Y_POSITION, "  <", 3, 0);
340
}
341
 
342
void draw_right_button(nstate *state)
343
{
344
        if(!state->running_buttons_mapped) return;
345
        GrFillRect(state->right_button, state->buttongcb, 0, 0,
346
                        RIGHT_BUTTON_WIDTH, RIGHT_BUTTON_HEIGHT);
347
        GrText(state->right_button, state->buttongcf, TEXT_X_POSITION,
348
                                        TEXT_Y_POSITION, "   >", 4, 0);
349
}
350
 
351
void draw_drop_button(nstate *state)
352
{
353
        if(!state->running_buttons_mapped) return;
354
        GrFillRect(state->drop_button, state->buttongcb, 0, 0,
355
                        DROP_BUTTON_WIDTH, DROP_BUTTON_HEIGHT);
356
        GrText(state->drop_button, state->buttongcf, TEXT_X_POSITION,
357
                                        TEXT_Y_POSITION, "    Drop", 8, 0);
358
}
359
 
360
void draw_pause_continue_button(nstate *state)
361
{
362
        if((state->running_buttons_mapped) && (state->state == STATE_STOPPED)) {
363
                GrUnmapWindow(state->pause_continue_button);
364
                GrUnmapWindow(state->anticlockwise_button);
365
                GrUnmapWindow(state->clockwise_button);
366
                GrUnmapWindow(state->left_button);
367
                GrUnmapWindow(state->right_button);
368
                GrUnmapWindow(state->drop_button);
369
                state->running_buttons_mapped = 0;
370
                return;
371
        }
372
        if((!state->running_buttons_mapped) && (state->state == STATE_RUNNING)){
373
                GrMapWindow(state->pause_continue_button);
374
                GrMapWindow(state->anticlockwise_button);
375
                GrMapWindow(state->clockwise_button);
376
                GrMapWindow(state->left_button);
377
                GrMapWindow(state->right_button);
378
                GrMapWindow(state->drop_button);
379
                state->running_buttons_mapped = 1;
380
                return;
381
        }
382
        if(!state->running_buttons_mapped) return;
383
        GrFillRect(state->pause_continue_button, state->buttongcb, 0, 0,
384
                PAUSE_CONTINUE_BUTTON_WIDTH, PAUSE_CONTINUE_BUTTON_HEIGHT);
385
        if(state->state == STATE_PAUSED) {
386
                GrText(state->pause_continue_button, state->buttongcf,
387
                        TEXT_X_POSITION, TEXT_Y_POSITION, " Continue", 9, 0);
388
        } else {
389
                GrText(state->pause_continue_button, state->buttongcf,
390
                        TEXT_X_POSITION, TEXT_Y_POSITION, "   Pause", 8, 0);
391
        }
392
}
393
 
394
int block_is_all_in_well(nstate *state)
395
{
396
        if(state->current_shape.y >= WELL_NOTVISIBLE)
397
                return 1;
398
 
399
        return 0;
400
}
401
 
402
void delete_line(nstate *state, int line)
403
{
404
        int x, y;
405
 
406
        if(line < WELL_NOTVISIBLE) return;
407
 
408
        for(y = line - 1; y; y--)
409
                for(x = WELL_WIDTH; x; x--)
410
                        state->blocks[0][y + 1][x] = state->blocks[0][y][x];
411
 
412
        draw_well(state, 0);
413
}
414
 
415
void block_reached_bottom(nstate *state)
416
{
417
        int x, y;
418
 
419
        if(!block_is_all_in_well(state)) {
420
                state->state = STATE_STOPPED;
421
                return;
422
        }
423
 
424
        for(y = WELL_HEIGHT - 1; y; y--) {
425
                for(x = 0; x < WELL_WIDTH; x++)
426
                        if(!state->blocks[0][y][x]) goto nr;
427
                msleep(DELETE_LINE_DELAY);
428
                delete_line(state, y);
429
                state->score += SCORE_INCREMENT;
430
                if((LEVELS > (state->level + 1)) && (((state->level + 1) *
431
                                        LEVEL_DIVISOR) <= state->score))
432
                        state->level++;
433
                draw_score(state);
434
                y++;
435
                nr:
436
        }
437
 
438
        choose_new_shape(state);
439
        draw_next_shape(state);
440
}
441
 
442
void move_block(nstate *state, int direction)
443
{
444
        if(direction == 0) {
445
                if(!state->current_shape.x) return;
446
                else {
447
                        if(!will_collide(state, (state->current_shape.x - 1),
448
                                                state->current_shape.y,
449
                                        state->current_shape.orientation)) {
450
                                draw_shape(state, state->current_shape.x,
451
                                                state->current_shape.y, 1);
452
                                state->current_shape.x--;
453
                                draw_shape(state, state->current_shape.x,
454
                                                state->current_shape.y, 0);
455
                                draw_well(state, 0);
456
                        }
457
                }
458
        } else {
459
                if(!will_collide(state, (state->current_shape.x + 1),
460
                                                state->current_shape.y,
461
                                        state->current_shape.orientation)) {
462
                        draw_shape(state, state->current_shape.x,
463
                                        state->current_shape.y, 1);
464
                        state->current_shape.x++;
465
                        draw_shape(state, state->current_shape.x,
466
                                        state->current_shape.y, 0);
467
                        draw_well(state, 0);
468
                }
469
        }
470
}
471
 
472
void rotate_block(nstate *state, int direction)
473
{
474
        int neworientation = 0;
475
 
476
        if(direction == 0) {
477
                if(!state->current_shape.orientation)
478
                        neworientation = MAXORIENTATIONS - 1;
479
                else neworientation = state->current_shape.orientation - 1;
480
        } else {
481
                neworientation = state->current_shape.orientation + 1;
482
                if(neworientation == MAXORIENTATIONS) neworientation = 0;
483
        }
484
 
485
        if(!will_collide(state, state->current_shape.x, state->current_shape.y,
486
                                                        neworientation)) {
487
                draw_shape(state, state->current_shape.x,
488
                                state->current_shape.y, 1);
489
                state->current_shape.orientation = neworientation;
490
                draw_shape(state, state->current_shape.x,
491
                                state->current_shape.y, 0);
492
                draw_well(state, 0);
493
        }
494
}
495
 
496
int drop_block_1(nstate *state)
497
{
498
        if(will_collide(state, state->current_shape.x,
499
                                (state->current_shape.y + 1),
500
                                state->current_shape.orientation)) {
501
                block_reached_bottom(state);
502
                return 1;
503
        }
504
 
505
        draw_shape(state, state->current_shape.x, state->current_shape.y, 1);
506
        state->current_shape.y++;
507
        draw_shape(state, state->current_shape.x, state->current_shape.y, 0);
508
 
509
        draw_well(state, 0);
510
 
511
        return 0;
512
}
513
 
514
void drop_block(nstate *state)
515
{
516
        while(!drop_block_1(state)) msleep(DROP_BLOCK_DELAY);
517
}
518
 
519
void handle_exposure_event(nstate *state)
520
{
521
        GR_EVENT_EXPOSURE *event = &state->event.exposure;
522
 
523
        if(event->wid == state->score_window) {
524
                draw_score(state);
525
                return;
526
        }
527
        if(event->wid == state->next_shape_window) {
528
                draw_next_shape(state);
529
                return;
530
        }
531
        if(event->wid == state->new_game_button) {
532
                draw_new_game_button(state);
533
                return;
534
        }
535
        if(event->wid == state->pause_continue_button) {
536
                draw_pause_continue_button(state);
537
                return;
538
        }
539
        if(event->wid == state->anticlockwise_button) {
540
                draw_anticlockwise_button(state);
541
                return;
542
        }
543
        if(event->wid == state->clockwise_button) {
544
                draw_clockwise_button(state);
545
                return;
546
        }
547
        if(event->wid == state->left_button) {
548
                draw_left_button(state);
549
                return;
550
        }
551
        if(event->wid == state->right_button) {
552
                draw_right_button(state);
553
                return;
554
        }
555
        if(event->wid == state->drop_button) {
556
                draw_drop_button(state);
557
                return;
558
        }
559
        if(event->wid == state->well_window) {
560
                draw_well(state, 1);
561
                return;
562
        }
563
}
564
 
565
void handle_mouse_event(nstate *state)
566
{
567
        GR_EVENT_MOUSE *event = &state->event.mouse;
568
 
569
        if(event->wid == state->new_game_button) {
570
                state->state = STATE_NEWGAME;
571
                return;
572
        }
573
        if(event->wid == state->pause_continue_button) {
574
                if(state->state == STATE_PAUSED) state->state = STATE_RUNNING;
575
                else state->state = STATE_PAUSED;
576
                return;
577
        }
578
        if(event->wid == state->anticlockwise_button) {
579
                if(state->state == STATE_PAUSED) state->state = STATE_RUNNING;
580
                rotate_block(state, 0);
581
                return;
582
        }
583
        if(event->wid == state->clockwise_button) {
584
                if(state->state == STATE_PAUSED) state->state = STATE_RUNNING;
585
                rotate_block(state, 1);
586
                return;
587
        }
588
        if(event->wid == state->left_button) {
589
                if(state->state == STATE_PAUSED) state->state = STATE_RUNNING;
590
                move_block(state, 0);
591
                return;
592
        }
593
        if(event->wid == state->right_button) {
594
                if(state->state == STATE_PAUSED) state->state = STATE_RUNNING;
595
                move_block(state, 1);
596
                return;
597
        }
598
        if(event->wid == state->drop_button) {
599
                if(state->state == STATE_PAUSED) state->state = STATE_RUNNING;
600
                drop_block(state);
601
                return;
602
        }
603
}
604
 
605
void handle_keyboard_event(nstate *state)
606
{
607
        GR_EVENT_KEYSTROKE *event = &state->event.keystroke;
608
 
609
        switch(event->ch) {
610
                case 'q':
611
                case 'Q':
612
                case MWKEY_CANCEL:
613
                        state->state = STATE_EXIT;
614
                        return;
615
                case 'n':
616
                case 'N':
617
                case MWKEY_APP1:
618
                        state->state = STATE_NEWGAME;
619
                        return;
620
        }
621
 
622
        if(state->state == STATE_STOPPED) return;
623
 
624
        state->state = STATE_RUNNING;
625
 
626
        switch(event->ch) {
627
                case 'p':
628
                case 'P':
629
                        state->state = STATE_PAUSED;
630
                        break;
631
                case 'j':
632
                case 'J':
633
                case MWKEY_LEFT:
634
                        move_block(state, 0);
635
                        break;
636
                case 'k':
637
                case 'K':
638
                case MWKEY_RIGHT:
639
                        move_block(state, 1);
640
                        break;
641
                case 'd':
642
                case 'D':
643
                case MWKEY_UP:
644
                        rotate_block(state, 0);
645
                        break;
646
                case 'f':
647
                case 'F':
648
                case MWKEY_DOWN:
649
                        rotate_block(state, 1);
650
                        break;
651
                case ' ':
652
                case MWKEY_MENU:
653
                        drop_block(state);
654
                        break;
655
        }
656
}
657
 
658
void handle_event(nstate *state)
659
{
660
        switch(state->event.type) {
661
                case GR_EVENT_TYPE_EXPOSURE:
662
                        handle_exposure_event(state);
663
                        break;
664
                case GR_EVENT_TYPE_BUTTON_DOWN:
665
                        handle_mouse_event(state);
666
                        break;
667
                case GR_EVENT_TYPE_KEY_DOWN:
668
                        handle_keyboard_event(state);
669
                        break;
670
                case GR_EVENT_TYPE_CLOSE_REQ:
671
                        state->state = STATE_EXIT;
672
                        break;
673
                case GR_EVENT_TYPE_TIMEOUT:
674
                        break;
675
                default:
676
                        fprintf(stderr, "Unhandled event type %d\n",
677
                                                        state->event.type);
678
                        break;
679
        }
680
}
681
 
682
void clear_well(nstate *state)
683
{
684
        int x, y;
685
 
686
        for(y = 0; y < WELL_HEIGHT; y++)
687
                for(x = 0; x < WELL_WIDTH; x++) {
688
                        state->blocks[0][y][x] = 0;
689
                        state->blocks[1][y][x] = 0;
690
                }
691
}
692
 
693
/* Dirty hack alert- this is to avoid using any floating point math */
694
int random8(int limit)
695
{
696
        int ret;
697
 
698
        do { ret = random() & 7; } while(ret > limit);
699
 
700
        return ret;
701
}
702
 
703
void choose_new_shape(nstate *state)
704
{
705
        state->current_shape.type = state->next_shape.type;
706
        state->current_shape.orientation = state->next_shape.orientation;
707
        state->current_shape.colour = state->next_shape.colour;
708
        state->current_shape.x = (WELL_WIDTH / 2) - 2;
709
        state->current_shape.y = WELL_NOTVISIBLE -
710
                        shape_sizes[state->next_shape.type]
711
                                [state->next_shape.orientation][1] - 1;
712
        state->next_shape.type = random8(MAXSHAPES - 1);
713
        state->next_shape.orientation = random8(MAXORIENTATIONS - 1);
714
        state->next_shape.colour = block_colours[random8(MAX_BLOCK_COLOUR)];
715
}
716
 
717
void new_game(nstate *state)
718
{
719
        clear_well(state);
720
        if(state->score > state->hiscore) state->hiscore = state->score;
721
        state->score = 0;
722
        state->level = 0;
723
        draw_score(state);
724
        choose_new_shape(state);
725
        draw_next_shape(state);
726
        draw_well(state, 1);
727
        if(state->state == STATE_NEWGAME) state->state = STATE_RUNNING;
728
}
729
 
730
void init_game(nstate *state)
731
{
732
        GR_WM_PROPERTIES props;
733
 
734
        if(GrOpen() < 0) {
735
                fprintf(stderr, "Couldn't connect to Nano-X server\n");
736
                exit(1);
737
        }
738
 
739
        state->main_window = GrNewWindow(GR_ROOT_WINDOW_ID,
740
                                        MAIN_WINDOW_X_POSITION,
741
                                        MAIN_WINDOW_Y_POSITION,
742
                                        MAIN_WINDOW_WIDTH,
743
                                        MAIN_WINDOW_HEIGHT, 0,
744
                                        MAIN_WINDOW_BACKGROUND_COLOUR, 0);
745
        /* set title */
746
        props.flags = GR_WM_FLAGS_TITLE | GR_WM_FLAGS_PROPS;
747
        props.props = GR_WM_PROPS_BORDER | GR_WM_PROPS_CAPTION;
748
        props.title = "Nano-Tetris";
749
        GrSetWMProperties(state->main_window, &props);
750
        GrSelectEvents(state->main_window, GR_EVENT_MASK_EXPOSURE |
751
                                        GR_EVENT_MASK_CLOSE_REQ |
752
                                        GR_EVENT_MASK_KEY_DOWN |
753
                                        GR_EVENT_MASK_TIMEOUT);
754
 
755
        state->score_window = GrNewWindow(state->main_window,
756
                                        SCORE_WINDOW_X_POSITION,
757
                                        SCORE_WINDOW_Y_POSITION,
758
                                        SCORE_WINDOW_WIDTH,
759
                                        SCORE_WINDOW_HEIGHT, 0,
760
                                        SCORE_WINDOW_BACKGROUND_COLOUR, 0);
761
        GrSelectEvents(state->score_window, GR_EVENT_MASK_EXPOSURE);
762
        GrMapWindow(state->score_window);
763
        state->scoregcf = GrNewGC();
764
        GrSetGCForeground(state->scoregcf, SCORE_WINDOW_FOREGROUND_COLOUR);
765
        GrSetGCBackground(state->scoregcf, SCORE_WINDOW_BACKGROUND_COLOUR);
766
        state->scoregcb = GrNewGC();
767
        GrSetGCForeground(state->scoregcb, SCORE_WINDOW_BACKGROUND_COLOUR);
768
 
769
        state->next_shape_window = GrNewWindow(state->main_window,
770
                                        NEXT_SHAPE_WINDOW_X_POSITION,
771
                                        NEXT_SHAPE_WINDOW_Y_POSITION,
772
                                        NEXT_SHAPE_WINDOW_WIDTH,
773
                                        NEXT_SHAPE_WINDOW_HEIGHT, 0,
774
                                        NEXT_SHAPE_WINDOW_BACKGROUND_COLOUR, 0);
775
        GrSelectEvents(state->next_shape_window, GR_EVENT_MASK_EXPOSURE);
776
        GrMapWindow(state->next_shape_window);
777
        state->nextshapegcf = GrNewGC();
778
        state->nextshapegcb = GrNewGC();
779
        GrSetGCForeground(state->nextshapegcb,
780
                                NEXT_SHAPE_WINDOW_BACKGROUND_COLOUR);
781
 
782
        state->new_game_button = GrNewWindow(state->main_window,
783
                                        NEW_GAME_BUTTON_X_POSITION,
784
                                        NEW_GAME_BUTTON_Y_POSITION,
785
                                        NEW_GAME_BUTTON_WIDTH,
786
                                        NEW_GAME_BUTTON_HEIGHT, 0,
787
                                        BUTTON_BACKGROUND_COLOUR, 0);
788
        GrSelectEvents(state->new_game_button, GR_EVENT_MASK_EXPOSURE |
789
                                        GR_EVENT_MASK_BUTTON_DOWN);
790
        GrMapWindow(state->new_game_button);
791
        state->buttongcf = GrNewGC();
792
        GrSetGCForeground(state->buttongcf, BUTTON_FOREGROUND_COLOUR);
793
        GrSetGCBackground(state->buttongcf, BUTTON_BACKGROUND_COLOUR);
794
        state->buttongcb = GrNewGC();
795
        GrSetGCForeground(state->buttongcb, BUTTON_BACKGROUND_COLOUR);
796
 
797
        state->pause_continue_button = GrNewWindow(state->main_window,
798
                                        PAUSE_CONTINUE_BUTTON_X_POSITION,
799
                                        PAUSE_CONTINUE_BUTTON_Y_POSITION,
800
                                        PAUSE_CONTINUE_BUTTON_WIDTH,
801
                                        PAUSE_CONTINUE_BUTTON_HEIGHT, 0,
802
                                        BUTTON_BACKGROUND_COLOUR, 0);
803
        GrSelectEvents(state->pause_continue_button, GR_EVENT_MASK_EXPOSURE |
804
                                        GR_EVENT_MASK_BUTTON_DOWN);
805
 
806
        state->anticlockwise_button = GrNewWindow(state->main_window,
807
                                        ANTICLOCKWISE_BUTTON_X_POSITION,
808
                                        ANTICLOCKWISE_BUTTON_Y_POSITION,
809
                                        ANTICLOCKWISE_BUTTON_WIDTH,
810
                                        ANTICLOCKWISE_BUTTON_HEIGHT, 0,
811
                                        BUTTON_BACKGROUND_COLOUR,
812
                                        0);
813
        GrSelectEvents(state->anticlockwise_button, GR_EVENT_MASK_EXPOSURE |
814
                                        GR_EVENT_MASK_BUTTON_DOWN);
815
 
816
        state->clockwise_button = GrNewWindow(state->main_window,
817
                                        CLOCKWISE_BUTTON_X_POSITION,
818
                                        CLOCKWISE_BUTTON_Y_POSITION,
819
                                        CLOCKWISE_BUTTON_WIDTH,
820
                                        CLOCKWISE_BUTTON_HEIGHT, 0,
821
                                        BUTTON_BACKGROUND_COLOUR,
822
                                        0);
823
        GrSelectEvents(state->clockwise_button, GR_EVENT_MASK_EXPOSURE |
824
                                        GR_EVENT_MASK_BUTTON_DOWN);
825
 
826
        state->left_button = GrNewWindow(state->main_window,
827
                                        LEFT_BUTTON_X_POSITION,
828
                                        LEFT_BUTTON_Y_POSITION,
829
                                        LEFT_BUTTON_WIDTH,
830
                                        LEFT_BUTTON_HEIGHT, 0,
831
                                        BUTTON_BACKGROUND_COLOUR,
832
                                        0);
833
        GrSelectEvents(state->left_button, GR_EVENT_MASK_EXPOSURE |
834
                                        GR_EVENT_MASK_BUTTON_DOWN);
835
 
836
        state->right_button = GrNewWindow(state->main_window,
837
                                        RIGHT_BUTTON_X_POSITION,
838
                                        RIGHT_BUTTON_Y_POSITION,
839
                                        RIGHT_BUTTON_WIDTH,
840
                                        RIGHT_BUTTON_HEIGHT, 0,
841
                                        BUTTON_BACKGROUND_COLOUR,
842
                                        0);
843
        GrSelectEvents(state->right_button, GR_EVENT_MASK_EXPOSURE |
844
                                        GR_EVENT_MASK_BUTTON_DOWN);
845
 
846
        state->drop_button = GrNewWindow(state->main_window,
847
                                        DROP_BUTTON_X_POSITION,
848
                                        DROP_BUTTON_Y_POSITION,
849
                                        DROP_BUTTON_WIDTH,
850
                                        DROP_BUTTON_HEIGHT, 0,
851
                                        BUTTON_BACKGROUND_COLOUR,
852
                                        0);
853
        GrSelectEvents(state->drop_button, GR_EVENT_MASK_EXPOSURE |
854
                                        GR_EVENT_MASK_BUTTON_DOWN);
855
 
856
        state->well_window = GrNewWindow(state->main_window,
857
                                        WELL_WINDOW_X_POSITION,
858
                                        WELL_WINDOW_Y_POSITION,
859
                                        WELL_WINDOW_WIDTH,
860
                                        WELL_WINDOW_HEIGHT, 0,
861
                                        WELL_WINDOW_BACKGROUND_COLOUR, 0);
862
        GrSelectEvents(state->well_window, GR_EVENT_MASK_EXPOSURE);
863
        GrMapWindow(state->well_window);
864
        state->wellgc = GrNewGC();
865
 
866
        GrMapWindow(state->main_window);
867
 
868
        state->state = STATE_STOPPED;
869
        state->score = 0;
870
        read_hiscore(state);
871
        state->level = 0;
872
        state->running_buttons_mapped = 0;
873
 
874
        srandom(time(0));
875
 
876
        choose_new_shape(state);
877
        new_game(state);
878
}
879
 
880
void calculate_timeout(nstate *state)
881
{
882
        struct timeval t;
883
        long u;
884
 
885
        gettimeofday(&t, NULL);
886
        u = t.tv_usec + (delays[state->level] * 1000);
887
        state->timeout.tv_sec = t.tv_sec + (u / 1000000);
888
        state->timeout.tv_usec = u % 1000000;
889
}
890
 
891
unsigned long timeout_delay(nstate *state)
892
{
893
        struct timeval t;
894
        signed long s, m, ret;
895
 
896
        gettimeofday(&t, NULL);
897
 
898
        if((t.tv_sec > state->timeout.tv_sec) ||
899
                        ((t.tv_sec == state->timeout.tv_sec) &&
900
                        t.tv_usec >= state->timeout.tv_usec)) return 1;
901
 
902
        s = state->timeout.tv_sec - t.tv_sec;
903
        m = ((state->timeout.tv_usec - t.tv_usec) / 1000);
904
        ret = (unsigned long)((1000 * s) + m);
905
/*
906
        fprintf(stderr, "t.tv_sec = %ld, t.tv_usec = %ld, timeout.tv_sec = "
907
                "%ld, timeout.tv_usec = %ld, s = %ld, m = %ld, ret = %ld\n",
908
                t.tv_sec, t.tv_usec, state->timeout.tv_sec,
909
                state->timeout.tv_usec, s, m, ret);
910
*/
911
        if(ret <= 0) return 1;
912
        else return ret;
913
}
914
 
915
void do_update(nstate *state)
916
{
917
        struct timeval t;
918
 
919
        gettimeofday(&t, NULL);
920
 
921
        if((t.tv_sec > state->timeout.tv_sec) ||
922
                        ((t.tv_sec == state->timeout.tv_sec) &&
923
                        (t.tv_usec >= state->timeout.tv_usec))) {
924
                drop_block_1(state);
925
                calculate_timeout(state);
926
        }
927
}
928
 
929
void do_pause(nstate *state)
930
{
931
        draw_pause_continue_button(state);
932
        while(state->state == STATE_PAUSED) {
933
                GrGetNextEvent(&state->event);
934
                handle_event(state);
935
        }
936
        draw_pause_continue_button(state);
937
}
938
 
939
void wait_for_start(nstate *state)
940
{
941
        draw_pause_continue_button(state);
942
        while(state->state == STATE_STOPPED) {
943
                GrGetNextEvent(&state->event);
944
                handle_event(state);
945
        }
946
        if(state->state == STATE_NEWGAME) state->state = STATE_RUNNING;
947
        draw_pause_continue_button(state);
948
        calculate_timeout(state);
949
}
950
 
951
void run_game(nstate *state)
952
{
953
        while(state->state == STATE_RUNNING) {
954
                GrGetNextEventTimeout(&state->event, timeout_delay(state));
955
                handle_event(state);
956
                if(state->state == STATE_PAUSED) do_pause(state);
957
                if(state->state == STATE_RUNNING) do_update(state);
958
        }
959
}
960
 
961
void main_game_loop(nstate *state)
962
{
963
        wait_for_start(state);
964
        while(state->state != STATE_EXIT) {
965
                if(state->state == STATE_RUNNING) run_game(state);
966
                if(state->state == STATE_STOPPED) wait_for_start(state);
967
                if(state->state != STATE_EXIT) new_game(state);
968
        }
969
}
970
 
971
int main(int argc, char *argv[])
972
{
973
        nstate *state = my_malloc(sizeof(nstate));
974
 
975
        init_game(state);
976
        main_game_loop(state);
977
 
978
        write_hiscore(state);
979
 
980
        GrClose();
981
 
982
        return 0;
983
}

powered by: WebSVN 2.1.0

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