aboutsummaryrefslogtreecommitdiffstats
path: root/src/snake_map.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/snake_map.cpp')
-rw-r--r--src/snake_map.cpp245
1 files changed, 245 insertions, 0 deletions
diff --git a/src/snake_map.cpp b/src/snake_map.cpp
new file mode 100644
index 0000000..8a104eb
--- /dev/null
+++ b/src/snake_map.cpp
@@ -0,0 +1,245 @@
+#include "snake_map.h"
+
+void SnakeMap::main_init(MainData * md) {
+ mdata = md;
+
+ end();
+ reset_all();
+}
+
+void SnakeMap::draw() {
+ fl_rectf(x(), y(), w(), h(), color());
+ fl_rect(x(), y(), w(), h(), 0x0);
+
+ draw_snake(mdata, snake_blocks);
+ draw_snack(mdata, this, snack);
+}
+
+int SnakeMap::handle(int event) {
+ switch (event) {
+ case FL_FOCUS:
+ case FL_UNFOCUS:
+ return 1;
+ case FL_KEYDOWN:
+
+ if (mdata->paused)
+ goto end_of_keydown;
+
+ switch (Fl::event_key()) {
+ case FL_Right:
+ if (direction != SNAKE_LEFT)
+ direction = SNAKE_RIGHT;
+
+ break;
+ case FL_Left:
+ if (direction != SNAKE_RIGHT)
+ direction = SNAKE_LEFT;
+
+ break;
+ case FL_Up:
+ if (direction != SNAKE_DOWN)
+ direction = SNAKE_UP;
+
+ break;
+ case FL_Down:
+ if (direction != SNAKE_UP)
+ direction = SNAKE_DOWN;
+
+ break;
+ default:
+ break;
+ }
+
+end_of_keydown: // Yes I know. goto sucks.
+ mdata->win->handle(FL_SHORTCUT); // A hack for keyboard shortcuts.
+ return 1;
+ case FL_KEYUP:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+void SnakeMap::update() {
+ int i;
+ SnakeBlock block_behind;
+ SNAKE_DIR snake_dir;
+
+ if (mdata->paused)
+ return;
+
+ // Set head direction.
+ snake_blocks.front().current_direction = direction;
+
+ // Update snake blocks.
+ for (i = 0; i < snake_blocks.size(); i++) {
+
+ // Update direction.
+ snake_dir = snake_blocks[i].current_direction;
+
+ // Go to update_position if head.
+ if (i == 0)
+ goto update_position;
+
+ block_behind = snake_blocks[i - 1];
+
+ switch (block_behind.current_direction) {
+ case SNAKE_STILL:
+ break;
+ case SNAKE_RIGHT:
+ snake_dir = (snake_blocks[i].y > block_behind.y) ? SNAKE_UP : SNAKE_DOWN;
+
+ // Set to same direction.
+ if (abs(snake_blocks[i].y - block_behind.y) <= mdata->settings.snake_speed)
+ snake_dir = SNAKE_RIGHT;
+ break;
+ case SNAKE_LEFT:
+ snake_dir = (snake_blocks[i].y > block_behind.y) ? SNAKE_UP : SNAKE_DOWN;
+
+ if (abs(snake_blocks[i].y - block_behind.y) <= mdata->settings.snake_speed)
+ snake_dir = SNAKE_LEFT;
+ break;
+ case SNAKE_UP:
+ snake_dir = (snake_blocks[i].x > block_behind.x) ? SNAKE_LEFT : SNAKE_RIGHT;
+
+ if (abs(snake_blocks[i].x - block_behind.x) <= mdata->settings.snake_speed)
+ snake_dir = SNAKE_UP;
+ break;
+ case SNAKE_DOWN:
+ snake_dir = (snake_blocks[i].x > block_behind.x) ? SNAKE_LEFT : SNAKE_RIGHT;
+
+ if (abs(snake_blocks[i].x - block_behind.x) <= mdata->settings.snake_speed)
+ snake_dir = SNAKE_DOWN;
+ break;
+ default:
+ break;
+ }
+
+ // Set new direction value.
+ snake_blocks[i].current_direction = snake_dir;
+ put_snake_blocks_side_by_side(mdata->settings.tile_size, &snake_blocks[i], block_behind);
+
+update_position:
+ // Update position.
+ switch (snake_dir) {
+ case SNAKE_STILL:
+ break;
+ case SNAKE_RIGHT:
+ snake_blocks[i].x += mdata->settings.snake_speed;
+ break;
+ case SNAKE_LEFT:
+ snake_blocks[i].x -= mdata->settings.snake_speed;
+ break;
+ case SNAKE_UP:
+ snake_blocks[i].y -= mdata->settings.snake_speed;
+ break;
+ case SNAKE_DOWN:
+ snake_blocks[i].y += mdata->settings.snake_speed;
+ break;
+ default:
+ break;
+ }
+
+ // Hit self (but not the first and second block).
+ if (mdata->settings.die_when_hit_self && i > 2)
+ if (snake_blocks_hit(mdata->settings.tile_size, snake_blocks.front(), snake_blocks[i])) {
+ reset_all();
+ return;
+ }
+ }
+
+ // Check is out of bounds.
+ if (snake_block_out_of_bounds(snake_blocks.front())) {
+ reset_all();
+ return;
+ }
+
+ // Eat yummies.
+ if (snake_block_eat_snack(mdata->settings.tile_size, this, snake_blocks.front(), snack)) {
+ reset_snack();
+ add_snake_block();
+ return;
+ }
+}
+
+void SnakeMap::reset_size() {
+ w(mdata->settings.tile_size * mdata->settings.tile_count_w);
+ h(mdata->settings.tile_size * mdata->settings.tile_count_h);
+
+ // Center.
+ position(
+ (mdata->win->w() / 2) - (w() / 2),
+ (mdata->win->h() / 2) - (h() / 2)
+ );
+
+ mdata->win->redraw();
+}
+
+void SnakeMap::reset_snake() {
+ direction = SNAKE_STILL;
+ snake_blocks.clear();
+
+ // Create snake head.
+ SnakeBlock head_block;
+ head_block.part = SNAKE_HEAD;
+ head_block.current_direction = SNAKE_STILL;
+
+ // Center snake.
+ head_block.x = x() + (w() / 2);
+ head_block.y = y() + (h() / 2);
+
+ snake_blocks.push_back(head_block);
+ update_length_output();
+}
+
+void SnakeMap::reset_snack() {
+ snack.type = (SNACK_TYPE)random_range(0, SNACK_COUNT);
+ snack.x = random_range(0, mdata->settings.tile_count_w - 1);
+ snack.y = random_range(0, mdata->settings.tile_count_h - 1);
+}
+
+void SnakeMap::reset_all() {
+ reset_size();
+ reset_snake();
+ reset_snack();
+}
+
+bool SnakeMap::snake_block_out_of_bounds(SnakeBlock snake_block) {
+ int tile_size = mdata->settings.tile_size;
+
+ bool x_out = (snake_block.x < x()) | (snake_block.x + tile_size > x() + w());
+ bool y_out = (snake_block.y < y()) | (snake_block.y + tile_size > y() + h());
+
+ return x_out | y_out;
+}
+
+void SnakeMap::add_snake_block() {
+ SnakeBlock block_behind;
+ block_behind = snake_blocks.back();
+
+ if (snake_blocks.size() > 1)
+ snake_blocks.back().part = SNAKE_BODY;
+
+ // Create new block.
+ SnakeBlock new_block;
+ new_block.part = SNAKE_TAIL;
+ new_block.current_direction = block_behind.current_direction;
+
+ // Set position.
+ put_snake_blocks_side_by_side(mdata->settings.tile_size, &new_block, block_behind);
+
+ snake_blocks.push_back(new_block);
+ update_length_output();
+}
+
+void SnakeMap::update_length_output() {
+ if (mdata->length_output == NULL)
+ return;
+
+ char buf[NAME_MAX];
+ memset(buf, 0, NAME_MAX);
+
+ snprintf(buf, NAME_MAX, "%d", snake_blocks.size() - 1); // Head does not
+ // count.
+ mdata->length_output->value(buf);
+}