+
+static void update_cur_block(void)
+{
+ if(cur_block < 0) return;
+
+ memcpy(pos, next_pos, sizeof pos);
+ prev_rot = cur_rot;
+}
+
+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(x < 0 || x >= PF_COLS || y >= PF_ROWS) return 1;
+ 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<PF_COLS; j++) {
+ if(!(pfline[j] & PF_FULL)) {
+ nblank++;
+ }
+ }
+
+ if(nblank == 0) {
+ complines[num_complines++] = y;
+ }
+ }
+
+ /*snd_stick();*/
+
+ if(num_complines) {
+ addscore(num_complines);
+ }
+}
+
+static void erase_completed(void)
+{
+ int i, j, srow, drow;
+ unsigned int *pfstart = pfield;
+ unsigned int *dptr;
+
+ /* sort completed lines from highest to lowest row number */
+ for(i=0; i<num_complines-1; i++) {
+ for(j=i+1; j<num_complines; j++) {
+ if(complines[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; i<PF_ROWS; i++) {
+ for(j=0; j<num_complines; j++) {
+ if(complines[j] == srow) {
+ srow--;
+ }
+ }
+
+ if(srow < 0) {
+ for(j=0; j<PF_COLS; j++) {
+ dptr[j] &= ~PF_FULL;
+ }
+
+ } else if(srow != drow) {
+ unsigned int *sptr = pfstart + srow * PF_COLS;
+ memcpy(dptr, sptr, PF_COLS * sizeof *dptr);
+ }
+
+ srow--;
+ drow--;
+ dptr -= PF_COLS;
+ }
+}
+