#include "solve_screen.h" #include "../../game_state.h" #include "play_screen.h" uint8_t target_foundation; static double accumulated_delta = 0; static Vector animation_target = VECTOR_ZERO; static Vector animation_from = VECTOR_ZERO; void start_solve_screen(void* data) { UNUSED(data); accumulated_delta = 0; target_foundation = 0; } void render_solve_screen(void* data) { GameState* state = (GameState*)data; render_play_screen(state); if(state->animated_card.card) { card_render_front( state->animated_card.card, (uint8_t)state->animated_card.position.x, (uint8_t)state->animated_card.position.y, false, state->buffer, 22); } } bool end_solve_screen(GameState* state) { for(uint8_t i = 0; i < 4; i++) { Card* c = list_peek_back(state->foundation[i]); if(!c || c->value != KING) return false; } return true; } static int8_t missing_suit(GameState* state) { bool found[4] = {false, false, false, false}; for(uint8_t i = 0; i < 4; i++) { if(state->foundation[i]->count) { Card* c = list_peek_back(state->foundation[i]); found[c->suit] = true; } } for(int8_t i = 0; i < 4; i++) { if(!found[i]) return i; } return -1; } static void quick_solve(GameState* state) { //remove all cards that are not placed to the foundation yet list_free_data(state->deck); list_free_data(state->waste); for(uint8_t i = 0; i < 7; i++) { list_free_data(state->tableau[i]); } list_free_data(state->hand); state->animated_card.card = NULL; //fill up the foundations with cards for(uint8_t i = 0; i < 4; i++) { //add ace to the start if(state->foundation[i]->count == 0) { Card* c = malloc(sizeof(Card)); c->value = ACE; c->suit = missing_suit(state); c->exposed = true; list_push_back(c, state->foundation[i]); } //fill up the rest for(uint8_t v = state->foundation[i]->count; v < 13; v++) { Card* c = malloc(sizeof(Card)); c->value = v - 1; c->suit = ((Card*)list_peek_back(state->foundation[i]))->suit; c->exposed = true; list_push_back(c, state->foundation[i]); } } end_solve_screen(state); } static bool animation_done(GameState* state) { if(!state->animated_card.card) return true; accumulated_delta += state->delta_time * 4; vector_lerp( &(animation_from), &animation_target, accumulated_delta, &(state->animated_card.position)); double dist = vector_distance(&(state->animated_card.position), &animation_target); return dist < 1; } static Card* find_and_remove(List* list, uint8_t suit, uint8_t value) { //go reversed order because tableau will always have at the end ListItem* current = list->tail; while(current) { if(((Card*)current->data)->value == value && ((Card*)current->data)->suit == suit) { Card* c = current->data; list_remove_item(c, list); return c; } current = current->prev; } return NULL; } static uint8_t positions[9] = {2, 20, 2, 20, 38, 56, 74, 92, 110}; static void find_next_card(GameState* state) { List* order[9] = { state->deck, state->waste, state->tableau[0], state->tableau[1], state->tableau[2], state->tableau[3], state->tableau[4], state->tableau[5], state->tableau[6]}; int8_t missing = missing_suit(state); if(missing >= 0) { //find the missing ACE for(uint8_t id = 0; id < 9; id++) { Card* ace = find_and_remove(order[id], missing, ACE); if(ace) { ace->exposed = true; for(uint8_t i = 0; i < 4; i++) { if(state->foundation[i]->count == 0) { state->animated_card.card = ace; target_foundation = i; animation_from.x = positions[id]; animation_from.y = id < 2 ? 1 : ((float)MIN( (uint8_t)state->tableau[state->selected[0]]->count, 4) * 4 + 15); state->animated_card.position = animation_from; animation_target.x = (float)(56 + target_foundation * 18); animation_target.y = 1; } } } } } else { uint8_t lowestValue = 14, lowestSuit = 0; //get the lowest value for(uint8_t i = 0; i < 4; i++) { Card* c = list_peek_back(state->foundation[i]); if(lowestValue > ((c->value + 1) % 13)) { lowestValue = ((c->value + 1) % 13); target_foundation = i; lowestSuit = c->suit; } } //store that card to animate for(uint8_t id = 0; id < 9; id++) { Card* c = find_and_remove(order[id], lowestSuit, lowestValue); if(c) { state->animated_card.card = c; animation_from.x = positions[id]; animation_from.y = id < 2 ? 1 : ((float)MIN((uint8_t)state->tableau[state->selected[0]]->count, 4) * 4 + 15); state->animated_card.position = animation_from; animation_target.x = (float)(56 + target_foundation * 18); animation_target.y = 1; break; } } } } void update_solve_screen(void* data) { GameState* state = (GameState*)data; state->isDirty = true; if(!end_solve_screen(state)) { if(animation_done(state)) { if(state->animated_card.card) { state->animated_card.card->exposed = true; list_push_back(state->animated_card.card, state->foundation[target_foundation]); state->animated_card.card = NULL; accumulated_delta = 0; } find_next_card(state); } } else { state->scene_switch = 1; } } void input_solve_screen(void* data, InputKey key, InputType type) { if(key == InputKeyOk && type == InputTypePress) { quick_solve(data); } }