#include #include #include #include #include #include "draw.h" #include "collide.h" #include "levels.h" #include "player.h" #include "menu.h" #include "shared_define.h" #define MAX_HSPD 2.5 #define DRILL_HSPD 6.0 #define ACCELERATION 1.0 #define DECELERATION 0.5 #define MIN_VSPD -12.0 #define MAX_VSPD 6.0 #define JUMP_SPD -3.99 #define GRAV 0.4 #define JUMP_SCALE 8 #define JUMP_REDUCTION -0.41 #define DRAW_LEVEL() draw_level(level, step, polarity, &start_x, &start_y, tp_positions) void dupdate(); //gint function //test if jump pressed int sgn(int number); //return the sign of input double int callback(volatile void *arg) { volatile int *has_ticked = arg; *has_ticked = 1; return 0; } int main(void) { volatile int has_ticked = 1; //fps cap char level[477]; int level_id = 5050; char jump_pressed = 1; //avoid holding jump char jump_buffer = 0; //jump buffer, last 3 frames unsigned int jump_hold = 0; //number of consecutive frames jump has been held double vspd = 0.0; //player vertical speed double hspd = 0; //player horizontal speed int move = 0; int on_ground = 6; //remember if player is on solid char in_water = 0; int player_x = 0; int player_y = 0; int start_x = 18*16 + 2; int start_y = 9*16 + 4; char spawn_buffer = 0; unsigned int step = 0; unsigned int rem_step = 0; char pswap_held = 0; char polarity = 0; //0 -> blue, 1 -> red char enable_up_key = 0; char game_loop = 1; char exit_buffer = 0; char tp_buffer = 0; int tp_positions[4] = { 0, 0, 0, 0 }; char directions[4] = { 0, 0, 0, 0 }; char last_direction = RIGHT; char selected_direction = RIGHT; char drill_buffer = 0; char drill_toggle = 0; int drill_x = 0; int drill_y = 0; set_level(level_id, level); DRAW_LEVEL(); player_x = start_x; player_y = start_y; //fps cap timer timer_setup(0, timer_delay(0, 1000000/FPS), 0, callback, &has_ticked); timer_start(0); while (game_loop) { while(!has_ticked) sleep(); has_ticked = 0; //START DRAW step++; if (!(step % 2)) { DRAW_LEVEL(); draw_player(player_x, player_y); //drill if (drill_toggle) draw_player(drill_x, drill_y); draw_timer(step/2); dupdate(); } //END DRAW clearevents(); //direction inputs if (keydown(KEY_LEFT)) { if (!directions[LEFT]) last_direction = LEFT; directions[LEFT] += 1; } else directions[LEFT] = 0; if (keydown(KEY_RIGHT)) { if (!directions[RIGHT]) last_direction = RIGHT; directions[RIGHT] += 1; } else directions[RIGHT] = 0; if (keydown(KEY_UP)) { if (!directions[UP]) last_direction = UP; directions[UP] += 1; } else directions[UP] = 0; if (keydown(KEY_DOWN)) { if (!directions[DOWN]) last_direction = DOWN; directions[DOWN] += 1; } else directions[DOWN] = 0; //direction inputs END //polarity swap first if (keydown(KEY_OPTN)) { if (!pswap_held) { pswap_held = 1; polarity = !polarity; } } else pswap_held = 0; //drill toggling if (keydown(KEY_ALPHA)) { if (!drill_buffer) { drill_toggle = !drill_toggle; if (drill_toggle) selected_direction = last_direction; } drill_buffer = 1; } else drill_buffer = 0; //horizontal movement & collision { move = 0; double friction = 1; int trunc_hspd; //ice if (collide(player_x, player_y + 1, level, '~')) friction = 0.2; move = keydown(KEY_RIGHT) - keydown(KEY_LEFT); if (hspd < MAX_HSPD && hspd > -MAX_HSPD) { hspd += ACCELERATION * friction * move; } if (hspd > 0) { if (friction != 0.2) hspd -= DECELERATION * friction; else hspd -= DECELERATION / 4 * friction; if (hspd < 0) hspd = 0; } else if (hspd < 0) { if (friction != 0.2) hspd += DECELERATION * friction; else hspd += DECELERATION / 4 * friction; if (hspd > 0) hspd = 0; } trunc_hspd = hspd; if (1) //glue was here { if (!collide_solid(player_x + trunc_hspd, player_y, level, polarity, 0)) { player_x += trunc_hspd; } else { int sign_hspd = sgn(trunc_hspd); while (!collide_solid(player_x + sign_hspd, player_y, level, polarity, 0)) { player_x += sign_hspd; } hspd = 0; } } } //ground detection if (vspd >= 0 && collide_solid(player_x, player_y + 1, level, polarity, 1)) { on_ground = 6; vspd = 0; if (spawn_buffer) { spawn_buffer = 0; set_start_pos(&start_x, &start_y, player_x, player_y); } } else { if (on_ground != 6 && vspd < MAX_VSPD) vspd += GRAV; if (on_ground) on_ground--; } //in water? in_water = collide(player_x, player_y, level, 'w'); //vertical movement jump_test(&jump_pressed, &jump_buffer, &jump_hold, enable_up_key); //jump if (jump_buffer && (on_ground || in_water)) { vspd = JUMP_SPD; on_ground = 0; jump_hold = JUMP_SCALE; } else if (jump_hold && (keydown(KEY_SHIFT) || (keydown(KEY_UP) && enable_up_key))) { jump_hold--; vspd += JUMP_REDUCTION; } else jump_hold = 0; //elevator collision and raise if ((collide(player_x - 1, player_y, level, '^') || collide(player_x + 1, player_y, level, '^')) && vspd > MIN_VSPD) { if (vspd > -2) { vspd -= GRAV; } vspd -= GRAV; } //vertical collision { int trunc_vspd; if (in_water) trunc_vspd = vspd / 2; else trunc_vspd = vspd; //bouncer if (collide(player_x, player_y + trunc_vspd, level, '*')) { vspd = -vspd - 2; trunc_vspd = vspd; } if (trunc_vspd) { if (!collide_solid(player_x, player_y + trunc_vspd, level, polarity, trunc_vspd > 0)) { player_y += trunc_vspd; } else { int sign_vspd = sgn(trunc_vspd); while (!collide_solid(player_x, player_y + sign_vspd, level, polarity, vspd)) { player_y += sign_vspd; } vspd = 0; jump_hold = 0; } } } //teleporter if (collide(player_x, player_y, level, 't')) { if (!tp_buffer) { player_x = tp_positions[2] + 2; player_y = tp_positions[3] + 2; } tp_buffer = 1; } else if (collide(player_x, player_y, level, 'T')) { if (!tp_buffer) { player_x = tp_positions[0] + 2; player_y = tp_positions[1] + 2; } tp_buffer = 1; } else tp_buffer = 0; //drill logic if (drill_toggle) { drill_x = player_x; drill_y = player_y; switch (selected_direction) { case UP: drill_y -= 12; break; case DOWN: drill_y += 12; break; case LEFT: drill_x -= 12; break; case RIGHT: drill_x += 12; break; } collide_and_erase(drill_x, drill_y, level, 'd'); if (collide_spike(drill_x, drill_y, level) || collide_solid(drill_x, drill_y, level, polarity, 0)) { if (selected_direction == UP || selected_direction == DOWN) { vspd = -vspd; drill_toggle = 0; } else if (selected_direction == LEFT) hspd = DRILL_HSPD; else /*direction is RIGHT*/ hspd = -DRILL_HSPD; } } //spike collision and death if (collide_spike(player_x, player_y, level)) { player_x = start_x; player_y = start_y; polarity = 0; drill_toggle = 0; vspd = 0; } //border warp if (player_x <= 22) player_x = 414; else if (player_x >= 416) player_x = 24; else if (player_y <= 8) player_y = 246; else if (player_y >= 248) player_y = 10; //secret way/hidden passage collide_and_erase(player_x, player_y, level, 's'); //next level (exit) if (collide(player_x, player_y, level, 'E')) { level_id++; rem_step = step; if (level_id == LAST_LEVEL + 1) { just_breathe(step); return 0; } else { set_level(level_id, level); DRAW_LEVEL(); player_x = start_x; player_y = start_y; polarity = 0; drill_toggle = 0; vspd = 0; } } //menu if (keydown_any(KEY_EXIT, KEY_MENU, 0)) { if (!exit_buffer) { char reload = menu(&level_id, &enable_up_key, &game_loop, rem_step); if (reload) { if (level_id == 5050) { step = 0; } set_level(level_id, level); DRAW_LEVEL(); player_x = start_x; player_y = start_y; polarity = 0; vspd = 0; } exit_buffer = 1; } } else exit_buffer = 0; } gint_osmenu(); return 0; } int sgn(int number) { if (number < 0) return -1; else return 1; }