static void setup_game() { playing = true; Layer *window_layer = window_get_root_layer(window); layer_add_child(window_layer, s_bg_layer); layer_add_child(window_layer, s_left_pane_layer); layer_remove_from_parent(s_title_pane_layer); layer_remove_from_parent(text_layer_get_layer(new_game_label_layer)); layer_remove_from_parent(text_layer_get_layer(load_game_label_layer)); layer_remove_from_parent(text_layer_get_layer(high_score_layer)); layer_remove_from_parent(text_layer_get_layer(option_shadows_layer)); layer_add_child(window_layer, text_layer_get_layer(score_label_layer)); layer_add_child(window_layer, text_layer_get_layer(score_layer)); layer_add_child(window_layer, text_layer_get_layer(level_label_layer)); layer_add_child(window_layer, text_layer_get_layer(level_layer)); level = 0; lines_cleared = 0; text_layer_set_text(title_layer, ""); text_layer_set_text(score_label_layer, "Score"); update_num_layer(lines_cleared, scoreStr, score_layer); text_layer_set_text(level_label_layer, "Level"); update_num_layer(level, levelStr, level_layer); tick_time = max_tick; rotation = 0; nextBlockType = rand() % 7; drop_block(); layer_mark_dirty(s_bg_layer); layer_mark_dirty(s_left_pane_layer); }
/* * Controls the game gravity, and (attempts to)remove lines when a block * reaches the bottom. Indirectly creates new blocks, and updates points, * level, etc. * * Game is over when this function returns. */ void *blocks_loop(void *vp) { (void) vp; /* unused*/ int hit; struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 0; /* When we read in from the database, it sets the current level * for the game. Update the tick delay so we resume at proper * difficulty. */ update_tick_speed(); while (1) { ts.tv_nsec = pgame->nsec; nanosleep(&ts, NULL); if (pgame->lose || pgame->quit) break; pthread_mutex_lock(&pgame->lock); if (pgame->pause && pgame->pause_ticks) { pgame->pause_ticks--; goto draw_game; } /* Unpause the game if we're out of pause ticks */ pgame->pause = (pgame->pause && pgame->pause_ticks); unwrite_cur_block(); hit = drop_block(CURRENT_BLOCK()); write_cur_block(); if (hit == 0) { destroy_lines(); update_cur_block(); } else if (hit < 0) { exit(EXIT_FAILURE); } draw_game: screen_draw_game(); pthread_mutex_unlock(&pgame->lock); } /* remove the current piece from the board, when we write to the * database it would otherwise save the location of a block in mid-air. * We can't restore from blocks like that, so just remove it. */ unwrite_cur_block(); return NULL; }
static void drop_backlog(pa_memblockq *bq) { int64_t boundary; pa_assert(bq); boundary = bq->read_index - (int64_t) bq->maxrewind; while (bq->blocks && (bq->blocks->index + (int64_t) bq->blocks->chunk.length <= boundary)) drop_block(bq, bq->blocks); }
static void select_click_handler(ClickRecognizerRef recognizer, void *context) { if (!playing && lost) { restart_after_loss(); return; } if (!playing && !lost && (load_choice < 2)) { setup_game(); if (can_load && (load_choice == 1)) { load_game(); } if (!s_timer) { drop_block(); s_timer = app_timer_register(tick_time, game_tick, NULL); } return; } if (!playing && (load_choice == 2)) { // kamotswolf - had to modify several things in here to add new option option_shadows_buffer = !option_shadows_buffer; persist_write_bool(OPTION_SHADOWS_KEY, option_shadows_buffer); if(option_shadows_buffer) { text_layer_set_text(option_shadows_layer, "Drop Shadows ON"); } else { text_layer_set_text(option_shadows_layer, "Drop Shadows OFF"); } //layer_mark_dirty(s_title_pane_layer); return; } if (paused) { paused = false; s_timer = app_timer_register(tick_time, game_tick, NULL); layer_remove_from_parent(text_layer_get_layer(paused_label_layer)); return; } if (blockType == -1) { return; } GPoint newPos[4]; rotate_block(newPos, block, blockType, rotation); bool should_rotate = true; for (int i=0; i<4; i++) { if (newPos[i].x < 0 || newPos[i].x > 9) { should_rotate = false; } if (newPos[i].y < 0 || newPos[i].y > 19) { should_rotate = false; } if (grid[newPos[i].x][newPos[i].y]) { should_rotate = false; } } if (!should_rotate) { return; } for (int i=0; i<4; i++) { block[i] = newPos[i]; } rotation = (rotation + 1) % 4; layer_mark_dirty(s_left_pane_layer); }
void handle_keyboard_event(nstate *state) { GR_EVENT_KEYSTROKE *event = &state->event.keystroke; switch(event->ch) { case 'q': case 'Q': case MWKEY_CANCEL: state->state = STATE_EXIT; return; case 'n': case 'N': case MWKEY_APP1: state->state = STATE_NEWGAME; return; } if(state->state == STATE_STOPPED) return; state->state = STATE_RUNNING; switch(event->ch) { case 'p': case 'P': state->state = STATE_PAUSED; break; case 'j': case 'J': case MWKEY_LEFT: move_block(state, 0); break; case 'k': case 'K': case MWKEY_RIGHT: move_block(state, 1); break; case 'd': case 'D': case MWKEY_UP: rotate_block(state, 0); break; case 'f': case 'F': case MWKEY_DOWN: rotate_block(state, 1); break; case ' ': case MWKEY_MENU: drop_block(state); break; } }
/*! * @brief ゲームのメインループ * @param [in] sock 送信先ソケットのディスクリプタ */ int play_tetris(int sock) { static const uchar FLAG = GAMEOVER; /* ゲームオーバ時に送信する値 */ uint cnt = 1; /* カウンタ */ time_t base_time = time(NULL); /* ゲーム開始時刻を記憶 */ initialize(sock); /* 初期化 */ while (!gameover) { /* ゲームオーバーになるまでゲーム続行 */ static uchar enemy_field[STAGE_HEIGHT][STAGE_WIDTH]; /* 相手のフィールドデータを格納する2次元配列 */ time_t game_time; /* ゲームを開始してから、何秒経過したかを保持する */ /* キー入力があればそれに応じて操作 */ control_block(); /* 32回ループをしたら、ブロックを1マス落とす */ if ((cnt = (cnt + 1) % 32) == 0) { drop_block(); } write(sock, field, sizeof(field)); /* 自分のフィールドデータを送信 */ write(sock, &score, sizeof(score)); /* 自分のスコアを送信 */ read(sock, enemy_field, sizeof(enemy_field)); /* 相手のフィールドデータを受信 */ read(sock, &enemy_score, sizeof(enemy_score)); /* 相手のスコアを受信 */ show_field(enemy_field, ENEMY_FIELD_X); /* 相手のフィールドを描画する */ if (read_protocol(enemy_field[0][0])) { /* 特別な値を受信していないかチェックする */ sleep(1); return EXIT_SUCCESS; /* ゲーム終了 */ } print_score(ENEMY_SCORE_X, ENEMY_SCORE_Y, enemy_score); /* 相手のスコアを描画 */ if ((game_time = GAME_TIME - (time(NULL) - base_time)) == 0) { timeup(sock); sleep(1); return EXIT_SUCCESS; /* ゲーム終了 */ } print_time(game_time); /* ゲーム時間を表示する */ usleep(20000); /* 20000マイクロ秒停止する(この間、CPUに負荷をかけない) */ } write(sock, &FLAG, sizeof(FLAG)); /* 自分がゲームオーバになったことを相手に知らせる */ clear(); mvprintw(RESULT_STR_Y, RESULT_STR_X, "You lose!"); refresh(); sleep(2); endwin(); /* curses終了 */ puts("\nYou lose!"); sleep(1); return EXIT_SUCCESS; }
static void key_cb(SDL_Keycode k, int shift, struct game_state *gs) { switch (k) { case SDLK_r: init_game_state(gs); break; case SDLK_q: if (shift) end_cb(gs); break; case SDLK_j: case SDLK_s: drop_block(gs); break; case SDLK_h: case SDLK_a: move_x(gs, -1); break; case SDLK_l: case SDLK_d: move_x(gs, 1); break; case SDLK_k: case SDLK_w: rot_block(gs); break; } draw_cb(gs); }
void handle_mouse_event(nstate *state) { GR_EVENT_MOUSE *event = &state->event.mouse; if(event->wid == state->new_game_button) { state->state = STATE_NEWGAME; return; } if(event->wid == state->pause_continue_button) { if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; else state->state = STATE_PAUSED; return; } if(event->wid == state->anticlockwise_button) { if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; rotate_block(state, 0); return; } if(event->wid == state->clockwise_button) { if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; rotate_block(state, 1); return; } if(event->wid == state->left_button) { if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; move_block(state, 0); return; } if(event->wid == state->right_button) { if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; move_block(state, 1); return; } if(event->wid == state->drop_button) { if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; drop_block(state); return; } }
/* * 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; }
int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { struct list_item *q, *n; pa_memchunk chunk; int64_t old; pa_assert(bq); pa_assert(uchunk); pa_assert(uchunk->memblock); pa_assert(uchunk->length > 0); pa_assert(uchunk->index + uchunk->length <= pa_memblock_get_length(uchunk->memblock)); pa_assert(uchunk->length % bq->base == 0); pa_assert(uchunk->index % bq->base == 0); if (!can_push(bq, uchunk->length)) return -1; old = bq->write_index; chunk = *uchunk; fix_current_write(bq); q = bq->current_write; /* First we advance the q pointer right of where we want to * write to */ if (q) { while (bq->write_index + (int64_t) chunk.length > q->index) if (q->next) q = q->next; else break; } if (!q) q = bq->blocks_tail; /* We go from back to front to look for the right place to add * this new entry. Drop data we will overwrite on the way */ while (q) { if (bq->write_index >= q->index + (int64_t) q->chunk.length) /* We found the entry where we need to place the new entry immediately after */ break; else if (bq->write_index + (int64_t) chunk.length <= q->index) { /* This entry isn't touched at all, let's skip it */ q = q->prev; } else if (bq->write_index <= q->index && bq->write_index + (int64_t) chunk.length >= q->index + (int64_t) q->chunk.length) { /* This entry is fully replaced by the new entry, so let's drop it */ struct list_item *p; p = q; q = q->prev; drop_block(bq, p); } else if (bq->write_index >= q->index) { /* The write index points into this memblock, so let's * truncate or split it */ if (bq->write_index + (int64_t) chunk.length < q->index + (int64_t) q->chunk.length) { /* We need to save the end of this memchunk */ struct list_item *p; size_t d; /* Create a new list entry for the end of the memchunk */ if (!(p = pa_flist_pop(PA_STATIC_FLIST_GET(list_items)))) p = pa_xnew(struct list_item, 1); p->chunk = q->chunk; pa_memblock_ref(p->chunk.memblock); /* Calculate offset */ d = (size_t) (bq->write_index + (int64_t) chunk.length - q->index); pa_assert(d > 0); /* Drop it from the new entry */ p->index = q->index + (int64_t) d; p->chunk.length -= d; /* Add it to the list */ p->prev = q; if ((p->next = q->next)) q->next->prev = p; else bq->blocks_tail = p; q->next = p; bq->n_blocks++; } /* Truncate the chunk */ if (!(q->chunk.length = (size_t) (bq->write_index - q->index))) { struct list_item *p; p = q; q = q->prev; drop_block(bq, p); } /* We had to truncate this block, hence we're now at the right position */ break; } else { size_t d; pa_assert(bq->write_index + (int64_t)chunk.length > q->index && bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length && bq->write_index < q->index); /* The job overwrites the current entry at the end, so let's drop the beginning of this entry */ d = (size_t) (bq->write_index + (int64_t) chunk.length - q->index); q->index += (int64_t) d; q->chunk.index += d; q->chunk.length -= d; q = q->prev; } }
static void game_tick(void *data) { if (paused || !playing || lost) { return; } drop_block(); s_timer = app_timer_register(tick_time, game_tick, NULL); }