/* * Set up the required initial conditions for a match, and switch to playing state */ void start_game() { /* Seed the RNG */ srand(TCNT1); /* Load in the sprites */ reticule_SPR = reticule(0); /* Generate and draw a level */ clear_screen(); free((void*) level_map); level_map = generate_flat(WIDTH, 129); if(level_map != NULL) draw_level(level_map, SILVER, 0, WIDTH - 1); /* Set up the players in the field */ playersX = malloc(players * sizeof(int16_t)); playersY = malloc(players * sizeof(int16_t)); players_HP = malloc(players * sizeof(uint8_t)); if(playersX == NULL || playersY == NULL || players_HP == NULL) { display_string("Out of memory error!"); return; } uint8_t i; for(i = 0; i < players; i++) { playersX[i] = (i + 1) * WIDTH / (players + 1); playersY[i] = 120; players_HP[i] = MAX_PLAYER_HP; free_sprite(player_SPR); player_SPR = botleft(i); fill_sprite(player_SPR, playersX[i], playersY[i], HEIGHT_NO_UI, WIDTH); } /* Pick a random player to ... go last * First call to start_turn will cycle to next player. Poor sod. */ current_player = rand() % players; reticuleX = (playersX[current_player] + (RETICULE_DISTANCE * ml_cos(position))/100); reticuleY = (playersY[current_player] + (RETICULE_DISTANCE * ml_sin(position))/100); /* Initialise movement variables */ direction = 0; launch_speed = 0; /* Draw the UI */ display_string_xy("POWER:", POWER_LABEL_X, POWER_LABEL_Y); fill_rectangle(power_outline, WHITE); fill_rectangle(power_empty, BLACK); display_string_xy("WIND:", WIND_LABEL_X, WIND_LABEL_Y); fill_rectangle(wind_outline, WHITE); fill_rectangle(wind_empty, BLACK); /* Start the first player's turn */ start_turn(); }
static int prepare_sprite_surfaces(int fd, int sprite_width, int sprite_height, uint32_t num_surfaces, uint32_t *sprite_handles, uint32_t *sprite_stride, uint32_t *sprite_size, int tiled) { uint32_t bytes_per_pixel = sizeof(uint32_t); uint32_t *sprite_fb_ptr; int i; if (bytes_per_pixel != sizeof(uint32_t)) { printf("Bad bytes_per_pixel for sprite: %d\n", bytes_per_pixel); return -EINVAL; } if (tiled) { int v; /* Round the tiling up to the next power-of-two and the * region up to the next pot fence size so that this works * on all generations. * * This can still fail if the framebuffer is too large to * be tiled. But then that failure is expected. */ v = sprite_width * bytes_per_pixel; for (*sprite_stride = 512; *sprite_stride < v; *sprite_stride *= 2) ; v = *sprite_stride * sprite_height; for (*sprite_size = 1024*1024; *sprite_size < v; *sprite_size *= 2) ; } else { /* Scan-out has a 64 byte alignment restriction */ *sprite_stride = (sprite_width * bytes_per_pixel + 63) & ~63; *sprite_size = *sprite_stride * sprite_height; } for (i = 0; i < num_surfaces; i++) { // Create the sprite surface sprite_handles[i] = gem_create(fd, *sprite_size); if (tiled) gem_set_tiling(fd, sprite_handles[i], I915_TILING_X, *sprite_stride); // Get pointer to the surface sprite_fb_ptr = gem_mmap(fd, sprite_handles[i], *sprite_size, PROT_READ | PROT_WRITE); if (sprite_fb_ptr != NULL) { // Fill with checkerboard pattern fill_sprite(sprite_width, sprite_height, *sprite_stride, i, sprite_fb_ptr); munmap(sprite_fb_ptr, *sprite_size); } else { i--; while (i >= 0) { gem_close(fd, sprite_handles[i]); i--; } } } return 0; }
/* * Main function to run one tick of the game */ int run_game() { cli(); /* Movement phase */ if(game_state == 1) { /* Move the reticule based on readings from the rotary encoder */ int16_t newRX = (playersX[current_player] + (RETICULE_DISTANCE * ml_cos(position))/100); int16_t newRY = (playersY[current_player] + (RETICULE_DISTANCE * ml_sin(position))/100); rectangle reticuleOld = {reticuleX - reticule_SPR->width / 2, reticuleX + reticule_SPR->width / 2 - 1, reticuleY - reticule_SPR->height / 2, reticuleY + reticule_SPR->height / 2 - 1}; draw_background(level_map, SILVER, reticuleOld, HEIGHT_NO_UI, WIDTH); //fill_rectangle(reticuleOld, BLACK); if(newRX >= 0 && newRX < WIDTH && newRY >= 0 && newRY < HEIGHT) fill_sprite(reticule_SPR, newRX, newRY, HEIGHT_NO_UI, WIDTH); reticuleX = newRX; reticuleY = newRY; /* Read firing input */ if (get_switch_long(_BV(SWC))) { game_state = 3; return 0; } /* Read directional input.*/ if (get_switch_rpt(_BV(SWE))) { direction = 4; free_sprite(player_SPR); player_SPR = botright(current_player); } else if (get_switch_rpt(_BV(SWW))) { direction = -4; free_sprite(player_SPR); player_SPR = botleft(current_player); } else { direction = 0; return 0; } /* Move the player */ int16_t newX = playersX[current_player] + direction; int16_t newY = ml_min(level_map[newX - PLAYER_WIDTH], level_map[newX + PLAYER_WIDTH - 1]) - PLAYER_HEIGHT; int8_t i; int8_t player_collision = 0; for(i = 0; i < players; i++) { if(players_HP[i] != 0 && i != current_player && newX >= playersX[i] - PLAYER_WIDTH && newX <= playersX[i] + PLAYER_WIDTH - 1) { player_collision = 1; break; } } /* Cancel movement if trying to climb to high or off the sides of the screen */ if(player_collision || playersY[current_player] - newY > MAX_CLIMB_HEIGHT || newX <= PLAYER_WIDTH || newX + PLAYER_WIDTH > WIDTH) { /* DEBUGGING prints: */ //display_string_xy("Error\n", 10, 10); //ml_printf("Cannot move there... (%u,%u) to (%u,%u)", playersX[0], playersY[0], newX, newY); return 0; } rectangle playerOld = {playersX[current_player] - PLAYER_WIDTH, playersX[current_player] + PLAYER_WIDTH - 1, playersY[current_player] - PLAYER_HEIGHT, playersY[current_player] + PLAYER_HEIGHT - 1}; fill_rectangle(playerOld, BLACK); fill_sprite(player_SPR, newX, newY, HEIGHT_NO_UI, WIDTH); playersX[current_player] = newX; playersY[current_player] = newY; } /* Projectile phase (missile in the air) */ else if(game_state == 2) { /* Find the new position of the projectile */ int16_t newX = projectileX + proVelX/1000; int16_t newY = projectileY + proVelY/1000; rectangle projectileOld = {projectileX, projectileX, projectileY, projectileY}; fill_rectangle(projectileOld, BLACK); /* End turn if projectile goes off the sides of the level */ if(newX < 0 || newX > WIDTH) { start_turn(); return 0; } /* If the new position is in the ground, EXPLODE! * (Also, if off the bottom of the level) */ if(newY >= level_map[newX] || newY > HEIGHT_NO_UI) { int i; for(i = -EXPLOSION_RADIUS; i <= EXPLOSION_RADIUS; i++) { /* Make sure that terrain is on screen */ if(newX + i >= 0 && newX + i < WIDTH) { uint16_t new_ground_level = newY + ml_sqrt(EXPLOSION_RADIUS * EXPLOSION_RADIUS - i * i); if(new_ground_level >= HEIGHT_NO_UI) level_map[newX + i] = HEIGHT_NO_UI - 1; //Clamp to bottom of level else if(new_ground_level > level_map[newX + i]) //Don't raise the ground level! level_map[newX + i] = new_ground_level; } } draw_level(level_map, SILVER, newX - EXPLOSION_RADIUS, newX + EXPLOSION_RADIUS); /* Check players for damage + redraw them */ for(i = 0; i < players; i++) { int16_t deltaX = playersX[i] - newX; int16_t deltaY = playersY[i] - newY; int16_t distance = ml_sqrt(deltaX * deltaX + deltaY * deltaY); if(distance < BLAST_RADIUS) { int16_t damage = ml_clamp(0, players_HP[i], MAX_EXPLOSION_DAMAGE - (distance * MAX_EXPLOSION_DAMAGE / BLAST_RADIUS)); players_HP[i] -= damage; } rectangle playerOld = {playersX[i] - PLAYER_WIDTH, playersX[i] + PLAYER_WIDTH - 1, playersY[i] - PLAYER_HEIGHT, playersY[i] + PLAYER_HEIGHT - 1}; fill_rectangle(playerOld, BLACK); /* If the player is still alive, redraw them */ if(players_HP[i] != 0) { free_sprite(player_SPR); player_SPR = botleft(i); playersY[i] = ml_min(level_map[playersX[i] - PLAYER_WIDTH], level_map[playersX[i] + PLAYER_WIDTH - 1]) - PLAYER_HEIGHT; fill_sprite(player_SPR, playersX[i], playersY[i], HEIGHT_NO_UI, WIDTH); } } start_turn(); return 0; } rectangle projectileNew = {newX, newX, newY, newY}; /* Continue turn if off top of level, but only draw if projectile onscreen */ if(newY >= 0) { fill_rectangle(projectileNew, RED); } projectileX = newX; projectileY = newY; /* Apply gravity and wind */ proVelY += 500; proVelX += (wind_velocity - 10) * 50; } /* Charging phase */ else if(game_state == 3) { /* Increase the launch speed while the fire button is held */ if (get_switch_state(_BV(SWC))) { launch_speed++; rectangle bar = {POWER_BAR_START, POWER_BAR_START + launch_speed, 231, 236}; fill_rectangle(bar, WHITE); /* Fire once max power is reached */ if(launch_speed == 100) fire_projectile(); } else { fire_projectile(); } } /* Menu phase */ else if(game_state == 4) { if (get_switch_press(_BV(SWE))) { if(players == 4) players = 2; else players++; } else if (get_switch_press(_BV(SWW))) { if(players == 2) players = 4; else players--; } ml_printf_at("< %u Players >", 5, 115, players); if (get_switch_long(_BV(SWC))) { start_game(); } } /* End game phase */ else if(game_state == 5) { if (get_switch_long(_BV(SWC))) { start_menu(); } } sei(); return 0; }