/* * Tetris Guidlines say wallkicks first try to move left, attempt rotation * again. Then if that fails, we try again but by moving to the right. */ static int try_wall_kick(struct blocks *block, enum blocks_input_cmd cmd) { /* Try to move left and rotate again. */ if (translate_block(block, MOVE_LEFT) == 1) { if (rotate_block(block, cmd) == 1) return 1; } /* undo previous translation */ translate_block(block, MOVE_RIGHT); /* Try to move right and rotate again. */ if (translate_block(block, MOVE_RIGHT) == 1) { if (rotate_block(block, cmd) == 1) return 1; } return 0; }
void merge_group(struct group *group, struct group *child) { struct groupdata *groupdata = group->data; struct groupdata *childdata = child->data; for (size_t i = 0; i < ptrarray_count(childdata->blocks); ++i) { struct block *copy = copy_block(get_ptrarray(childdata->blocks, i)); translate_block(copy, &child->position); push_ptrarray(groupdata->blocks, copy); } for (size_t i = 0; i < ptrarray_count(childdata->groups); ++i) { struct group *copy = copy_group(get_ptrarray(childdata->groups, i)); vec3_add(©->position, ©->position, &child->position); insert_group(group, copy); } destroy_group(child); update_group_vertexarray(group); }
/* * User input. Hopefully self explanatory. * * Input keys are currently: * F1 pause * F3 quit * * wasdqe * - w hard drops a piece to the bottom. * - a/d move left/right respectively. * - s soft drops one row. * - qe rotate counter clockwise/clockwise repectively. * * - space is used to hold the currently falling block. */ void *blocks_input(void *vp) { (void) vp; /* unused */ int ch; if (!CURRENT_BLOCK()) return NULL; while ((ch = getch())) { /* prevent modification of the game from blocks_loop in the * other thread */ pthread_mutex_lock(&pgame->lock); switch (ch) { case KEY_F(1): pgame->pause = !pgame->pause; goto draw_game; case KEY_F(3): pgame->pause = false; pgame->quit = true; goto draw_game; } /* remove the current piece from the board */ unwrite_cur_block(); /* modify it */ switch (toupper(ch)) { case 'A': translate_block(CURRENT_BLOCK(), MOVE_LEFT); break; case 'D': translate_block(CURRENT_BLOCK(), MOVE_RIGHT); break; case 'S': if (drop_block(CURRENT_BLOCK())) CURRENT_BLOCK()->soft_drop++; else CURRENT_BLOCK()->lock_delay = 1E9 -1; break; case 'W': /* drop the block to the bottom of the game */ while (drop_block(CURRENT_BLOCK())) CURRENT_BLOCK()->hard_drop++; /* XXX */ CURRENT_BLOCK()->lock_delay = 1E9 -1; break; case 'Q': if (!rotate_block(CURRENT_BLOCK(), ROT_LEFT)) { try_wall_kick(CURRENT_BLOCK(), ROT_LEFT); } break; case 'E': if (!rotate_block(CURRENT_BLOCK(), ROT_RIGHT)) { try_wall_kick(CURRENT_BLOCK(), ROT_RIGHT); } break; case ' ': { struct blocks *tmp; /* We can hold each block exactly once */ if (CURRENT_BLOCK()->hold == true) break; tmp = CURRENT_BLOCK(); /* Effectively swap the first and second elements in * the linked list. The "Current Block" is element 2. * And the "Hold Block" is element 1. So we remove the * current block and reinstall it at the head, pushing * the hold block to the current position. */ LIST_REMOVE(tmp, entries); LIST_INSERT_HEAD(&pgame->blocks_head, tmp, entries); reset_block(HOLD_BLOCK()); HOLD_BLOCK()->hold = true; break; } } /* then rewrite it */ write_cur_block(); draw_game: screen_draw_game(); pthread_mutex_unlock(&pgame->lock); } return NULL; }
static void translate_block_(block *block, void *data) { translate_block(block, data); }