void panelbar_trigger_sprite(struct widget *self,s32 type,union trigparam *param) { bool force = 0; struct widget *boundwidget; int s; switch (type) { case PG_TRIGGER_ENTER: DATA->over = 1; break; case PG_TRIGGER_LEAVE: /* If we're dragging, the mouse didn't REALLY leave */ if (DATA->on) return; DATA->over=0; break; case PG_TRIGGER_DOWN: if (param->mouse.chbtn != 1) return; /* If we're bound to another widget (we should be) save its current size */ if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { DATA->oldsize = widget_get(boundwidget,PG_WP_SIZE); /* If we're not rolled up, save this as the unrolled split */ if (DATA->oldsize > DATA->minimum) DATA->unrolled = DATA->oldsize; } DATA->on = 1; DATA->x = param->mouse.x; DATA->y = param->mouse.y; DATA->draglen = 0; /* Update the screen now, so we have an up-to-date picture of the panelbar stored in DATA->s */ themeify_panelbar(self,1); VID(sprite_hideall) (); /* This line combined with the zero flag on */ update(NULL,0); /* the next gets a clean spriteless grab */ /* In case there was no release trigger (bug in input driver) */ if (DATA->s) { free_sprite(DATA->s); DATA->s = NULL; } if (DATA->sbit) { VID(bitmap_free) (DATA->sbit); DATA->sbit = NULL; } /* Allocate the new sprite */ if(iserror(new_sprite(&DATA->s,self->dt,DATA->panelbar->r.w,DATA->panelbar->r.h))) { DATA->s = NULL; return; } if (iserror(VID(bitmap_new) (&DATA->sbit,DATA->panelbar->r.w,DATA->panelbar->r.h,vid->bpp))) { free_sprite(DATA->s); DATA->s = NULL; DATA->sbit = NULL; return; } DATA->s->bitmap = &DATA->sbit; /* Grab a bitmap of the panelbar to use as the sprite */ VID(blit) (DATA->sbit,0,0,DATA->panelbar->r.w,DATA->panelbar->r.h, self->dt->display,DATA->s->x = DATA->panelbar->r.x,DATA->s->y = DATA->panelbar->r.y, PG_LGOP_NONE); /* Clip the sprite to the travel allowed by boundwidget's parent */ if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { DATA->s->clip_to = boundwidget->in; } return; case PG_TRIGGER_UP: case PG_TRIGGER_RELEASE: if (!DATA->on) return; if (!(param->mouse.chbtn & 1)) return; if (!iserror(rdhandle((void**)&boundwidget,PG_TYPE_WIDGET,self->owner, DATA->bindto)) && boundwidget) { s = panel_calcsplit(self,param->mouse.x,param->mouse.y, widget_get(boundwidget,PG_WP_SIDE)); if (DATA->draglen < MINDRAGLEN) { /* This was a click, not a drag */ DATA->over = 0; widget_set(boundwidget,PG_WP_SIZEMODE,PG_SZMODE_PIXEL); if (DATA->oldsize > DATA->minimum) /* Roll up the panel */ widget_set(boundwidget,PG_WP_SIZE,DATA->minimum); else /* Unroll the panel */ widget_set(boundwidget,PG_WP_SIZE,DATA->unrolled); } else { s += panel_effective_split(boundwidget->in); /* Save this as the new unrolled split, * Unless the user manually rolled up the panel */ if ((s-DATA->minimum) > MAXROLLUP) DATA->unrolled = s; else s = DATA->minimum; widget_set(boundwidget,PG_WP_SIZEMODE,PG_SZMODE_PIXEL); widget_set(boundwidget,PG_WP_SIZE,s); DATA->over = 1; } } VID(bitmap_free) (DATA->sbit); free_sprite(DATA->s); DATA->s = NULL; DATA->sbit = NULL; force = 1; /* Definitely draw the new position */ DATA->on = 0; break; case PG_TRIGGER_MOVE: case PG_TRIGGER_DRAG: if (!DATA->on) return; /* Ok, button 1 is dragging through our widget... */ if (panel_throttle(self)) return; /* Race condition prevention? * Without this, sometimes segfaults because DATA->s is NULL. * Possibly events_pending() triggered another event? */ if (!DATA->s) return; /* Determine where to blit the bar to... */ switch (self->in->flags & (~SIDEMASK)) { case PG_S_TOP: case PG_S_BOTTOM: DATA->s->x = DATA->panelbar->r.x; DATA->draglen += abs(param->mouse.y - DATA->y + DATA->panelbar->r.y - DATA->s->y); DATA->s->y = param->mouse.y - DATA->y + DATA->panelbar->r.y; break; case PG_S_LEFT: case PG_S_RIGHT: DATA->s->y = DATA->panelbar->r.y; DATA->draglen += abs(param->mouse.x - DATA->x + DATA->panelbar->r.x - DATA->s->x); DATA->s->x = param->mouse.x - DATA->x + DATA->panelbar->r.x; break; } /* Reposition sprite */ VID(sprite_update) (DATA->s); return; } themeify_panelbar(self,force); }
// Essa funcao eh executada apenas uma vez, no final, te dando a chance // de liberar a memoria das variaveis alocadas no jogo void fim() { free_sprite(enterprise); free_sprite(stars); free_sprite(dots); }
/* * 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; }
/* Free the sprites for the font */ void font_quit() { for (int i = 0; i < N_SEGMENTS; i++) { free_sprite(segments[i]); } }
/* * Checks to see if there are enough alive players to continue the game * If so, control switches to the next player */ void start_turn() { /* Update the HP UI */ draw_HP_UI(); /* Reset the power bar */ launch_speed = 0; fill_rectangle(power_empty, BLACK); /* If only one player remains, declare them winner. */ uint8_t i; uint8_t player_left; //Record last player left (meaningless if more than 1 survivor) uint8_t players_alive = 0; for(i = 0; i < players; i++) { if(players_HP[i] != 0) { players_alive++; player_left = i; } } if(players_alive == 1) { switch(player_left) { case 0: display_color(BLUE, BLACK); ml_printf_at("To the victor, the spoils! BLUE WINS!", 5, 20); break; case 1: display_color(RED, BLACK); ml_printf_at("And the win goes to RED! Congratulations!", 5, 20); break; case 2: display_color(YELLOW, BLACK); ml_printf_at("Who's the best? YELLOW's the best!", 5, 20); break; default: display_color(GREEN, BLACK); ml_printf_at("Looks like the others are GREEN with envy! (GREEN WINS)", 5, 20); break; } end_game(); return; } else if(players_alive == 0) { display_color(WHITE, BLACK); ml_printf_at("Oh dear, it looks like a DRAW!", 5, 20); end_game(); return; } /* Rotate through the players */ current_player = (current_player + 1) % players; while(players_HP[current_player] == 0) { current_player = (current_player + 1) % players; } /* Re-colour the reticule for the current player */ free_sprite(reticule_SPR); reticule_SPR = reticule(current_player); /* Change to movement phase */ game_state = 1; /* Generate a random(ish) wind for the turn */ wind_velocity = rand() % 21; rectangle *wind_bar = malloc(sizeof(rectangle)); uint16_t wind_colour; fill_rectangle(wind_empty, BLACK); if(wind_velocity < 10) { wind_bar->left = WIND_BAR_START + wind_velocity * 10; wind_bar->right = WIND_BAR_END; wind_bar->top = 231; wind_bar->bottom = 236; wind_colour = RED; } else if (wind_velocity > 10) { wind_bar->left = WIND_BAR_START; wind_bar->right = WIND_BAR_START + (wind_velocity - 10) * 10; wind_bar->top = 231; wind_bar->bottom = 236; wind_colour = BLUE; } else { free(wind_bar); return; } fill_rectangle(*wind_bar, wind_colour); free(wind_bar); }