From d151a7d42478d1e7f4c2e25422a1a1624ead0948 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Sat, 2 Mar 2019 17:00:07 +0200 Subject: [PATCH] foo --- src/blocks.h | 67 ++++++++++ src/gamescr.c | 407 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/screen.c | 2 + 3 files changed, 473 insertions(+), 3 deletions(-) create mode 100644 src/blocks.h diff --git a/src/blocks.h b/src/blocks.h new file mode 100644 index 0000000..0a76d37 --- /dev/null +++ b/src/blocks.h @@ -0,0 +1,67 @@ +#ifndef BLOCKS_H_ +#define BLOCKS_H_ + +#define BLK(x, y) ((x) | ((y) << 4)) +#define BLKX(c) ((unsigned char)(c) & 0xf) +#define BLKY(c) ((unsigned char)(c) >> 4) + +#define NUM_BLOCKS 7 + +static unsigned char blocks[NUM_BLOCKS][4][4] = { + /* L block */ + { + {BLK(0, 1), BLK(0, 2), BLK(1, 1), BLK(2, 1)}, + {BLK(0, 0), BLK(1, 0), BLK(1, 1), BLK(1, 2)}, + {BLK(0, 1), BLK(1, 1), BLK(2, 1), BLK(2, 0)}, + {BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(2, 2)} + }, + /* J block */ + { + {BLK(0, 1), BLK(1, 1), BLK(2, 1), BLK(2, 2)}, + {BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(0, 2)}, + {BLK(0, 0), BLK(0, 1), BLK(1, 1), BLK(2, 1)}, + {BLK(1, 0), BLK(2, 0), BLK(1, 1), BLK(1, 2)} + }, + /* I block */ + { + {BLK(0, 2), BLK(1, 2), BLK(2, 2), BLK(3, 2)}, + {BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(1, 3)}, + {BLK(0, 2), BLK(1, 2), BLK(2, 2), BLK(3, 2)}, + {BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(1, 3)} + }, + /* O block */ + { + {BLK(1, 1), BLK(2, 1), BLK(1, 2), BLK(2, 2)}, + {BLK(1, 1), BLK(2, 1), BLK(1, 2), BLK(2, 2)}, + {BLK(1, 1), BLK(2, 1), BLK(1, 2), BLK(2, 2)}, + {BLK(1, 1), BLK(2, 1), BLK(1, 2), BLK(2, 2)} + }, + /* Z block */ + { + {BLK(0, 1), BLK(1, 1), BLK(1, 2), BLK(2, 2)}, + {BLK(0, 1), BLK(1, 1), BLK(1, 0), BLK(0, 2)}, + {BLK(0, 1), BLK(1, 1), BLK(1, 2), BLK(2, 2)}, + {BLK(0, 1), BLK(1, 1), BLK(1, 0), BLK(0, 2)} + }, + /* S block */ + { + {BLK(1, 1), BLK(2, 1), BLK(0, 2), BLK(1, 2)}, + {BLK(0, 0), BLK(0, 1), BLK(1, 1), BLK(1, 2)}, + {BLK(1, 1), BLK(2, 1), BLK(0, 2), BLK(1, 2)}, + {BLK(0, 0), BLK(0, 1), BLK(1, 1), BLK(1, 2)} + }, + /* T block */ + { + {BLK(0, 1), BLK(1, 1), BLK(2, 1), BLK(1, 2)}, + {BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(0, 1)}, + {BLK(0, 1), BLK(1, 1), BLK(2, 1), BLK(1, 0)}, + {BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(2, 1)} + } +}; + +static int block_spawnpos[NUM_BLOCKS][2] = { + {-1, -2}, {-1, -2}, {-2, -2}, {-1, -2}, {-1, -2}, {-1, -2}, {-1, -2} +}; + + +#endif /* BLOCKS_H_ */ diff --git a/src/gamescr.c b/src/gamescr.c index 6e69c21..469fc12 100644 --- a/src/gamescr.c +++ b/src/gamescr.c @@ -1,6 +1,11 @@ +#include +#include +#include #include "opengl.h" +#include "game.h" #include "screen.h" #include "cmesh.h" +#include "blocks.h" static int init(void); static void cleanup(void); @@ -8,12 +13,20 @@ static void start(void); static void stop(void); static void update(float dt); static void draw(void); +static void draw_block(int block, const int *pos, int rot); +static void drawpf(void); static void reshape(int x, int y); static void keyboard(int key, int pressed); static void mouse(int bn, int pressed, int x, int y); static void motion(int x, int y); static void wheel(int dir); +static void addscore(int nlines); +static int spawn(void); +static int collision(int block, const int *pos); +static void stick(int block, const int *pos); +static void erase_completed(void); + struct game_screen game_screen = { "game", 1, /* opaque */ @@ -32,10 +45,39 @@ struct game_screen game_screen = { }; static struct cmesh *blkmesh; -static float cam_theta, cam_phi, cam_dist = 6; +static float cam_theta, cam_phi, cam_dist = 30; static int bnstate[16]; static int prev_mx, prev_my; +static long tick_interval; + +/* dimensions of the playfield */ +#define PF_ROWS 18 +#define PF_COLS 10 + +#define PF_FULL 0x100 +#define PF_VIS 0x200 +#define PF_VIS_SHIFT 9 + +static unsigned int pfield[PF_ROWS * PF_COLS]; + +static int pos[2], next_pos[2]; +static int cur_block, next_block, prev_block; +static int cur_rot, prev_rot; +static int complines[4]; +static int num_complines; +static int gameover; +static int pause; +static int score, level, lines; +static int just_spawned; + +#define NUM_LEVELS 21 +static const long level_speed[NUM_LEVELS] = { + 887, 820, 753, 686, 619, 552, 469, 368, 285, 184, + 167, 151, 134, 117, 107, 98, 88, 79, 69, 60, 50 +}; + + static int init(void) { if(!(blkmesh = cmesh_alloc())) { @@ -55,14 +97,97 @@ static void cleanup(void) static void start(void) { + srand(time(0)); + + pause = 0; + gameover = 0; + num_complines = 0; + score = level = lines = 0; + tick_interval = level_speed[0]; + cur_block = -1; + prev_block = 0; + next_block = rand() % NUM_BLOCKS; + + memset(pfield, 0, PF_COLS * PF_ROWS * sizeof *pfield); } static void stop(void) { } -static void update(float dt) +static void update(float dtsec) { + static long prev_tick; + long dt; + + if(pause) { + prev_tick = time_msec; + return; + } + dt = time_msec - prev_tick; + + /* + if(gameover) { + int i, row = PF_ROWS - gameover; + int *ptr; + + if(dt < GAMEOVER_FILL_RATE) { + return; + } + + if(row >= 0) { + ptr = pfield + row * PF_COLS; + for(i=0; i> 8; + + if(blink > 6) { + erase_completed(); + num_complines = 0; + return; + } + + for(i=0; i= tick_interval) { + if(cur_block >= 0) { + just_spawned = 0; + next_pos[0] = pos[0] + 1; + if(collision(cur_block, next_pos)) { + next_pos[0] = pos[0]; + stick(cur_block, next_pos); + return; + } + } else { + /* respawn */ + if(spawn() == -1) { + gameover = 1; + return; + } + } + + dt -= tick_interval; + prev_tick = time_msec; + } } static void draw(void) @@ -71,15 +196,153 @@ static void draw(void) glRotatef(cam_phi, 1, 0, 0); glRotatef(cam_theta, 0, 1, 0); - cmesh_draw(blkmesh); + /* center playfield */ + glPushMatrix(); + glTranslatef(-PF_COLS / 2, PF_ROWS / 2, 0); + + drawpf(); + if(cur_block >= 0) { + draw_block(cur_block, pos, cur_rot); + } + + glPopMatrix(); +} + +static void draw_block(int block, const int *pos, int rot) +{ + int i, pal; + unsigned char *p = blocks[block][rot]; + + /*pal = FIRST_BLOCK_PAL + block;*/ + + for(i=0; i<4; i++) { + int x = pos[1] + BLKX(*p); + int y = pos[0] + BLKY(*p); + p++; + + if(y < 0) continue; + + glPushMatrix(); + glTranslatef(x, y, 0); + cmesh_draw(blkmesh); + glPopMatrix(); + } +} + +static void drawpf(void) +{ + int i, j; + unsigned int *sptr = pfield; + + for(i=0; i= 0 && !just_spawned && !pause) { + next_pos[0] = pos[0] + 1; + if(collision(cur_block, next_pos)) { + next_pos[0] = pos[0]; + stick(cur_block, next_pos); /* stick immediately */ + } + } + break; + + case '\n': + case '\t': + if(!pause && cur_block >= 0) { + next_pos[0] = pos[0] + 1; + while(!collision(cur_block, next_pos)) { + next_pos[0]++; + } + next_pos[0]--; + stick(cur_block, next_pos); /* stick immediately */ + } + break; + + case 'p': + if(gameover) { + /* + if(score && is_highscore(score)) { + name = name_screen(score); + } + save_score(name, score, lines, level); + */ + /* TODO: pop screen */ + } else { + pause ^= 1; + } + break; + + case '\b': + /* + if(score && is_highscore(score)) { + name = name_screen(score); + } + save_score(name, score, lines, level); + */ + /* TODO: pop screen */ + break; + + default: + break; + } } static void mouse(int bn, int pressed, int x, int y) @@ -112,3 +375,141 @@ static void motion(int x, int y) static void wheel(int dir) { } + +static void addscore(int nlines) +{ + static const int stab[] = {40, 100, 300, 1200}; /* bonus per line completed */ + + assert(nlines < 5); + + score += stab[nlines - 1] * (level + 1); + lines += nlines; + + level = lines / 10; + if(level > NUM_LEVELS - 1) level = NUM_LEVELS - 1; + + tick_interval = level_speed[level]; +} + +static int spawn(void) +{ + int r, tries = 2; + + do { + r = rand() % NUM_BLOCKS; + } while(tries-- > 0 && (r | prev_block | next_block) == prev_block); + + cur_block = next_block; + next_block = r; + + prev_rot = cur_rot = 0; + pos[0] = block_spawnpos[cur_block][0]; + next_pos[0] = pos[0] + 1; + pos[1] = next_pos[1] = PF_COLS / 2 + block_spawnpos[cur_block][1]; + + if(collision(cur_block, next_pos)) { + return -1; + } + + just_spawned = 1; + return 0; +} + +static int collision(int block, const int *pos) +{ + int i; + unsigned char *p = blocks[block][cur_rot]; + + for(i=0; i<4; i++) { + int x = pos[1] + BLKX(*p); + int y = pos[0] + BLKY(*p); + p++; + + if(y < 0) continue; + + if(pfield[y * PF_COLS + x] & PF_FULL) return 1; + } + + return 0; +} + +static void stick(int block, const int *pos) +{ + int i, j, nblank; + unsigned int *pfline; + unsigned char *p = blocks[block][cur_rot]; + + num_complines = 0; + prev_block = cur_block; /* used by the spawn routine */ + cur_block = -1; + + for(i=0; i<4; i++) { + int x = pos[1] + BLKX(*p); + int y = pos[0] + BLKY(*p); + p++; + + pfline = pfield + y * PF_COLS; + pfline[x] = PF_FULL | PF_VIS | block; + + nblank = 0; + for(j=0; j complines[i]) { + int tmp = complines[j]; + complines[j] = complines[i]; + complines[i] = tmp; + } + } + } + + srow = drow = PF_ROWS - 1; + dptr = pfstart + drow * PF_COLS; + + for(i=0; istart(); return 0; } -- 1.7.10.4