#include "collide.h" #include "define.h" #include "drawlevel.h" #include "menu.h" #include "replace.h" #include "save.h" #include "setlevel.h" #include "times.h" #include "util.h" #include #include #include #include #include #include #define VACCELERATION 0.2 #define HACCELERATION 0.4 #define MAX_VSPD 9.0 #define FRICTION 0.2 static int callback(volatile int *frame_elapsed); static void end(unsigned int frame); static void game(int *id_level, char mode, char *type); int main(void) { static int run = 0; if (!run) { gint_world_switch(GINT_CALL(restore)); run = 1; } char mode = 0; char type = 1; const enum MenuCode valeur = start_menu(&type); switch (valeur) { case MenuLevelSel: { int id_level = 1; if (!speed_menu(&id_level)) { mode = 1; game(&id_level, mode, &type); } else main(); } break; case MenuAllMode: { int id_level = 1; mode = 0; game(&id_level, mode, &type); } break; case MenuTutorial: { int id_level = 0; mode = 1; game(&id_level, mode, &type); } break; case MenuExit: gint_world_switch(GINT_CALL(savefile)); break; } return 0; } static int callback(volatile int *frame_elapsed) { *frame_elapsed = 1; return TIMER_CONTINUE; } static void end(unsigned int frame) { draw_end((int)frame, 15, 2); sleep_ms(7000); main(); } static void game(int *id_level, char mode, char *type) { volatile int frame_elapsed = 1; int timer = timer_configure(TIMER_ANY, 1000000 / FPS, GINT_CALL(callback, &frame_elapsed)); timer_start(timer); char game_loop = 1; unsigned int frame = 0; int framelevel = 0; int player_x = 20, player_y = 20; char level[351]; char gravity = -1; // 1 down -1 up char check = 1; char blackout = 0; int start_x; int start_y; int death_count = 0; int coin = 0; char check_coin = 0; char double_check = 1; char chock = 0; int appear = 10; int disappear = 13; int nbswitch = 0; char check_nbswitch = 0; float vspd = 1.0; float hspd = 0.0; if (*id_level == 10 && *type != 3) *type = 2; else if (*type != 3) *type = 1; extern bopti_image_t img_speedrun; set_level(*id_level, level, &start_x, &start_y, &gravity, &appear, &disappear, &nbswitch); player_x = start_x; player_y = start_y; while (game_loop) { while (!frame_elapsed) sleep(); frame_elapsed = 0; frame++; framelevel++; if (!(frame % 2)) { draw_level(level); if (blackout) draw_blackout(player_x, player_y); if (blackout && *id_level == 0) { dtext(20, 20, C_WHITE, "You have touched the blackout item"); dtext(20, 40, C_WHITE, "it makes you partially blind"); dtext(20, 60, C_WHITE, "until your death :p"); } if (chock > 0 && *id_level == 0) { dtext(20, 165, C_BLACK, "You have touched the chock"); dtext(20, 180, C_BLACK, "item. It rotates your screen"); dtext(20, 195, C_BLACK, "horizontally and vertically"); } draw_player(player_x, player_y, *type); if (!mode) draw_timer(frame); else draw_timer(framelevel); if (!mode) dprint_opt(330, 0, C_RGB(255, 190, 0), C_BLACK, DTEXT_LEFT, DTEXT_TOP, "Coin : %d", coin); if (check_nbswitch) draw_nbswitch(nbswitch); dupdate(); } pollevent(); if (keydown(KEY_OPTN)) { replace_xy_block(player_x + 6, player_y + 6, 'd', level); death_count--; } // right and left collision if (keydown_any(KEY_RIGHT, KEY_LEFT, 0)) { float hbuff = 0.0; char signe = (keydown(KEY_RIGHT) - keydown(KEY_LEFT)); if (collide(player_x, player_y - 1, level, 'i') || collide(player_x, player_y + 1, level, 'i')) { hbuff += 0.12; } hspd *= 1 - FRICTION; hspd += signe * (HACCELERATION + hbuff); if (!collide_solid(player_x + round(hspd) + signe * 1, player_y, level)) player_x += round(hspd); else if (!collide_solid(player_x + signe * 1, player_y, level)) player_x += signe; if (player_x >= 388) player_x = -4; if (player_x < -9) player_x = 384; } else hspd = 0; // Action key if (keydown(KEY_SHIFT) && !check && nbswitch > 0 && ((collide_solid(player_x, player_y - 1, level) && gravity == -1) || (collide_solid(player_x, player_y + 1, level) && gravity))) { vspd = 1; if (gravity == -1) gravity = 1; else gravity = -1; if (check_nbswitch && nbswitch > 0) { nbswitch -= 1; } check = 1; } else if (!keydown(KEY_SHIFT) && check) check = 0; // gravity if (!collide_solid(player_x, player_y + ((int)vspd) * gravity + gravity, level)) { if (vspd < MAX_VSPD) vspd += VACCELERATION; if (collide(player_x + 1, player_y, level, 'i') || collide(player_x - 1, player_y, level, 'i')) vspd += 0.15; player_y += ((int)vspd) * gravity; } else if (!collide_solid(player_x, player_y + ((int)vspd) * gravity, level)) { vspd -= VACCELERATION; player_y += ((int)vspd) * gravity; } else if (!collide_solid(player_x, player_y + gravity, level)) { vspd = 1; player_y += 1 * gravity; } else vspd = 1; // Collide with dead block if (collide_dead(player_x, player_y, level)) { vspd = 1; player_x = start_x; player_y = start_y; if (check_coin) coin--; check_coin = 0; set_level(*id_level, level, &start_x, &start_y, &gravity, &appear, &disappear, &nbswitch); blackout = 0; check_nbswitch = 0; death_count++; double_check = 1; framelevel = 0; if (*id_level == 1 && !mode) frame = 0; } // Collide with the end if (collide_end(player_x, player_y, level)) { if (!mode && *id_level != 0) *id_level += 1; else break; check_coin = 0; set_level(*id_level, level, &start_x, &start_y, &gravity, &appear, &disappear, &nbswitch); player_x = start_x; player_y = start_y; check_nbswitch = 0; blackout = 0; double_check = 1; framelevel = 0; if (*id_level == 10 && *type == 1) *type = 2; else if (*type != 3) *type = 1; if (*id_level == LEVEL_MAX + 1) { timer_stop(timer); end(frame); } } // Collide with key1 = disappearance of blocks if (collide(player_x, player_y, level, 'k')) { replace_all_block('3', '0', level); replace_all_block('k', '0', level); } // Collide with key2 = appearance of blocks if (collide(player_x, player_y, level, 'K')) { replace_all_block('a', '4', level); replace_all_block('K', '0', level); } // Collide with coin if (collide(player_x, player_y, level, 't') && !check_coin) { replace_all_block('t', '0', level); check_coin = 1; coin++; } // Collide with blackout block if (collide(player_x, player_y, level, 'b')) { replace_all_block('b', '0', level); blackout = 1; } // Collide with nbswitch block if (collide(player_x, player_y, level, 'z')) { replace_all_block('z', '0', level); check_nbswitch = 1; } // Collide with change block if (collide_center(player_x, player_y, level, 'l')) { int x = 0; int y = 0; char level2[351] = {0}; int j = 0; replace_xy_block(player_x + 6, player_y + 6, 'P', level); for (int i = 349; i != -1; i--) { level2[j] = level[i]; j++; } del_level(level); strncpy(level, level2, 351); del_level(level2); int i = 0; while (i != 350) { switch (level[i]) { case 'P': player_x = x; player_y = y; level[i] = '0'; break; } x += TILE_HEIGHT; if (x == TILE_HEIGHT * LEVEL_WIDTH) { x = 0; y += TILE_HEIGHT; } i++; } if (gravity == -1) gravity = 1; else gravity = -1; chock++; } // Damaged block if (collide(player_x, player_y + (int)vspd + 2, level, 'B') && vspd >= 5) { if (level[((player_x) / 16) + ((player_y + 25) / 16) * 25] == 'B') replace_xy_block(player_x, player_y + 25, '0', level); if (level[((player_x + 12) / 16) + ((player_y + 25) / 16) * 25] == 'B' && collide_point(player_x + 12, player_y + 22, level, 'B')) replace_xy_block(player_x + 12, player_y + 25, '0', level); vspd = 1.0; } // Damaged block if (collide(player_x, player_y - (int)vspd - 2, level, 'B') && vspd >= 5) { if (level[((player_x) / 16) + ((player_y - (int)vspd - 2) / 16) * 25] == 'B') level[((player_x) / 16) + ((player_y - (int)vspd - 2) / 16) * 25] = '0'; if (level[((player_x + 12) / 16) + ((player_y - (int)vspd - 2) / 16) * 25] == 'B' && collide_point(player_x + 12, player_y - 12, level, 'B')) level[((player_x + 12) / 16) + ((player_y - (int)vspd - 2) / 16) * 25] = '0'; vspd = 1.0; } // Appear block collide_replace(player_x, player_y, level, 'h', 'y'); // Appear block if (!collide(player_x, player_y, level, 'y') && double_check) { for (int i = 0; level[i] != '\0'; i++) { if (level[i] == 'y' || level[i] == 'h') { double_check = 1; break; } else double_check = 0; } replace_all_block('y', 'H', level); } // Switch block if (collide_center(player_x, player_y, level, 'S')) { replace_xy_block(player_x + 6, player_y + 6, '0', level); vspd = 1.0; if (gravity == -1) gravity = 1; else gravity = -1; } if ((framelevel / FPS) > disappear - 1) { replace_all_block('c', '0', level); } if ((framelevel / FPS) > appear - 1) { replace_all_block('m', 'C', level); } // warp if (player_y >= 212) player_y = -4; if (player_y < -6) player_y = 212; // Menu if (keydown_any(KEY_EXIT, KEY_MENU, 0)) { char menu_loop = 1; char selected = 0; int Y_POS = 18; char buffer = 1; while (menu_loop) { clearevents(); dclear(C_WHITE); draw_level(level); draw_player(player_x, player_y, *type); dimage(0, 0, &img_speedrun); selected += keydown(KEY_DOWN) - keydown(KEY_UP); if (selected == 2) selected = 0; else if (selected == -1) selected = 1; dtext(32, Y_POS, C_BLACK, "CONTINUE"); if (!mode) dtext(32, Y_POS + 12, C_BLACK, "MENU"); else dtext(32, Y_POS + 12, C_BLACK, "SPEEDRUN MENU"); dtext(16, Y_POS + (selected * 12), C_BLACK, ">"); dprint(180, 45, C_BLACK, "LEVEL : %d", *id_level); dprint(320, 3, C_RGB(255, 178, 0), "COIN : %d", coin); dprint(311, 17, C_RGB(150, 16, 16), "DEATH : %d", death_count); dupdate(); if (keydown_any(KEY_SHIFT, KEY_EXE, 0)) { switch (selected) { case 0: menu_loop = 0; break; case 1: menu_loop = 0; game_loop = 0; break; } } if (keydown_any(KEY_EXIT, KEY_MENU, 0)) { if (!buffer) { menu_loop = 0; game_loop = 0; break; } } else buffer = 0; while (keydown_any(KEY_UP, KEY_DOWN, 0)) clearevents(); } } } timer_stop(timer); // when a level is quit if (mode) { if (*id_level == 0) { game_loop = 0; *id_level = 1; } // end of a level with level selection if (game_loop) { float framefloat = framelevel; draw_end(framelevel, *id_level, 0); savetime(framefloat, *id_level); sleep_ms(2500); } if (!speed_menu(id_level)) { mode = 1; death_count = 0; game(id_level, mode, type); } else main(); } else main(); }