solitaire.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #include <furi.h>
  2. #include <gui/gui.h>
  3. #include <input/input.h>
  4. #include <notification/notification_messages.h>
  5. #include "game_state.h"
  6. #include "src/util/list.h"
  7. #include "src/scene/scene_setup.h"
  8. #include "src/util/helpers.h"
  9. static List* game_logic;
  10. static ListItem* current_state;
  11. static FuriMutex* update_mutex;
  12. static void gui_input_events_callback(const void* value, void* ctx) {
  13. furi_mutex_acquire(update_mutex, FuriWaitForever);
  14. GameState* instance = ctx;
  15. const InputEvent* event = value;
  16. if(event->key == InputKeyBack && event->type == InputTypeLong) {
  17. FURI_LOG_W("INPUT", "EXIT");
  18. instance->exit = true;
  19. }
  20. if(current_state) {
  21. ((GameLogic*)current_state->data)->input(instance, event->key, event->type);
  22. }
  23. furi_mutex_release(update_mutex);
  24. }
  25. static GameState* prepare() {
  26. game_logic = list_make();
  27. update_mutex = (FuriMutex*)furi_mutex_alloc(FuriMutexTypeNormal);
  28. //Add scenes to the logic list
  29. list_push_back(&main_screen, game_logic);
  30. list_push_back(&intro_screen, game_logic);
  31. list_push_back(&play_screen, game_logic);
  32. list_push_back(&solve_screen, game_logic);
  33. list_push_back(&falling_screen, game_logic);
  34. list_push_back(&result_screen, game_logic);
  35. current_state = game_logic->head;
  36. GameState* instance = malloc(sizeof(GameState));
  37. ((GameLogic*)current_state->data)->start(instance);
  38. instance->hand = list_make();
  39. instance->deck = list_make();
  40. instance->waste = list_make();
  41. for(int i = 0; i < 7; i++) {
  42. if(i < 4) {
  43. instance->foundation[i] = list_make();
  44. }
  45. instance->tableau[i] = list_make();
  46. }
  47. instance->animated_card.position = VECTOR_ZERO;
  48. instance->animated_card.velocity = VECTOR_ZERO;
  49. instance->buffer = buffer_create(SCREEN_WIDTH, SCREEN_HEIGHT, false);
  50. instance->input = furi_record_open(RECORD_INPUT_EVENTS);
  51. instance->gui = furi_record_open(RECORD_GUI);
  52. instance->canvas = gui_direct_draw_acquire(instance->gui);
  53. instance->notification_app = (NotificationApp*)furi_record_open(RECORD_NOTIFICATION);
  54. notification_message_block(instance->notification_app, &sequence_display_backlight_enforce_on);
  55. instance->input_subscription =
  56. furi_pubsub_subscribe(instance->input, gui_input_events_callback, instance);
  57. return instance;
  58. }
  59. static void cleanup(GameState* instance) {
  60. furi_pubsub_unsubscribe(instance->input, instance->input_subscription);
  61. notification_message_block(
  62. instance->notification_app, &sequence_display_backlight_enforce_auto);
  63. list_free(instance->hand);
  64. list_free(instance->deck);
  65. list_free(instance->waste);
  66. for(int i = 0; i < 7; i++) {
  67. if(i < 4) {
  68. list_free(instance->foundation[i]);
  69. }
  70. list_free(instance->tableau[i]);
  71. }
  72. furi_mutex_free(update_mutex);
  73. instance->canvas = NULL;
  74. gui_direct_draw_release(instance->gui);
  75. furi_record_close(RECORD_GUI);
  76. furi_record_close(RECORD_INPUT_EVENTS);
  77. furi_record_close(RECORD_NOTIFICATION);
  78. list_clear(game_logic);
  79. free(game_logic);
  80. buffer_release(instance->buffer);
  81. free(instance);
  82. }
  83. static void next_scene(GameState* instance) {
  84. FURI_LOG_W("SCENE", "Next scene");
  85. current_state = current_state->next;
  86. if(current_state == NULL) {
  87. current_state = game_logic->head;
  88. }
  89. ((GameLogic*)current_state->data)->start(instance);
  90. }
  91. static void prev_scene(GameState* instance) {
  92. FURI_LOG_W("SCENE", "Prev scene");
  93. current_state = game_logic->head;
  94. if(current_state->prev == NULL) {
  95. instance->exit = true;
  96. return;
  97. }
  98. ((GameLogic*)current_state->data)->start(instance);
  99. }
  100. static void direct_draw_run(GameState* instance) {
  101. if(!check_pointer(instance)) return;
  102. size_t currFrameTime;
  103. size_t lastFrameTime = curr_time();
  104. instance->lateRender = false;
  105. furi_thread_set_current_priority(FuriThreadPriorityIdle);
  106. do {
  107. FuriStatus status = furi_mutex_acquire(update_mutex, 20);
  108. if(!status) continue;
  109. GameLogic* curr_state = (GameLogic*)current_state->data;
  110. currFrameTime = curr_time();
  111. instance->delta_time = (currFrameTime - lastFrameTime) / 64000000.0f;
  112. lastFrameTime = currFrameTime;
  113. check_pointer(curr_state);
  114. curr_state->update(instance);
  115. if(instance->scene_switch == 1) {
  116. next_scene(instance);
  117. } else if(instance->scene_switch == 2) {
  118. prev_scene(instance);
  119. }
  120. check_pointer(curr_state);
  121. check_pointer(instance);
  122. check_pointer(instance->canvas);
  123. check_pointer(instance->buffer);
  124. instance->scene_switch = 0;
  125. if(curr_state && instance->isDirty && instance->canvas && instance->buffer) {
  126. canvas_reset(instance->canvas);
  127. if(instance->lateRender) {
  128. buffer_swap_back(instance->buffer);
  129. buffer_render(instance->buffer, instance->canvas);
  130. curr_state->render(instance);
  131. } else {
  132. buffer_swap_back(instance->buffer);
  133. curr_state->render(instance);
  134. buffer_render(instance->buffer, instance->canvas);
  135. }
  136. canvas_commit(instance->canvas);
  137. if(instance->clearBuffer) buffer_clear(instance->buffer);
  138. instance->clearBuffer = true;
  139. instance->lateRender = false;
  140. instance->isDirty = false;
  141. }
  142. furi_mutex_release(update_mutex);
  143. furi_thread_yield();
  144. } while(!instance->exit);
  145. }
  146. int32_t solitaire_app(void* p) {
  147. UNUSED(p);
  148. int32_t return_code = 0;
  149. GameState* instance = prepare();
  150. direct_draw_run(instance);
  151. cleanup(instance);
  152. return return_code;
  153. }