world.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. #include <game/world.h>
  2. #include <game/storage.h>
  3. #include <flip_storage/storage.h>
  4. bool draw_json_world_furi(GameManager *manager, Level *level, const FuriString *json_data)
  5. {
  6. if (!json_data)
  7. {
  8. FURI_LOG_E("Game", "JSON data is NULL");
  9. return false;
  10. }
  11. int levels_added = 0;
  12. FURI_LOG_I("Game", "Looping through world data");
  13. for (int i = 0; i < MAX_WORLD_OBJECTS; i++)
  14. {
  15. FURI_LOG_I("Game", "Looping through world data: %d", i);
  16. FuriString *data = get_json_array_value_furi("json_data", i, json_data);
  17. if (!data)
  18. {
  19. break;
  20. }
  21. FuriString *icon = get_json_value_furi("icon", data);
  22. FuriString *x = get_json_value_furi("x", data);
  23. FuriString *y = get_json_value_furi("y", data);
  24. FuriString *amount = get_json_value_furi("amount", data);
  25. FuriString *horizontal = get_json_value_furi("horizontal", data);
  26. if (!icon || !x || !y || !amount || !horizontal)
  27. {
  28. FURI_LOG_E("Game", "Failed Data: %s", furi_string_get_cstr(data));
  29. if (data)
  30. furi_string_free(data);
  31. if (icon)
  32. furi_string_free(icon);
  33. if (x)
  34. furi_string_free(x);
  35. if (y)
  36. furi_string_free(y);
  37. if (amount)
  38. furi_string_free(amount);
  39. if (horizontal)
  40. furi_string_free(horizontal);
  41. level_clear(level);
  42. return false;
  43. }
  44. int count = atoi(furi_string_get_cstr(amount));
  45. if (count < 2)
  46. {
  47. // Just one icon
  48. spawn_icon(
  49. manager,
  50. level,
  51. furi_string_get_cstr(icon),
  52. atoi(furi_string_get_cstr(x)),
  53. atoi(furi_string_get_cstr(y)));
  54. }
  55. else
  56. {
  57. bool is_horizontal = (furi_string_cmp(horizontal, "true") == 0);
  58. spawn_icon_line(
  59. manager,
  60. level,
  61. furi_string_get_cstr(icon),
  62. atoi(furi_string_get_cstr(x)),
  63. atoi(furi_string_get_cstr(y)),
  64. count,
  65. is_horizontal,
  66. 17 // set as 17 for now
  67. );
  68. }
  69. furi_string_free(data);
  70. furi_string_free(icon);
  71. furi_string_free(x);
  72. furi_string_free(y);
  73. furi_string_free(amount);
  74. furi_string_free(horizontal);
  75. levels_added++;
  76. }
  77. FURI_LOG_I("Game", "Finished loading world data");
  78. return levels_added > 0;
  79. }
  80. static void draw_town_world(Level *level, GameManager *manager, void *context)
  81. {
  82. UNUSED(context);
  83. if (!manager || !level)
  84. {
  85. FURI_LOG_E("Game", "Manager or level is NULL");
  86. return;
  87. }
  88. GameContext *game_context = game_manager_game_context_get(manager);
  89. level_clear(level);
  90. FuriString *json_data_str = furi_string_alloc();
  91. furi_string_cat_str(json_data_str, "{\"name\":\"shadow_woods_v5\",\"author\":\"ChatGPT\",\"json_data\":[{\"icon\":\"rock_medium\",\"x\":100,\"y\":100,\"amount\":10,\"horizontal\":true},{\"icon\":\"rock_medium\",\"x\":400,\"y\":300,\"amount\":6,\"horizontal\":true},{\"icon\":\"rock_small\",\"x\":600,\"y\":200,\"amount\":8,\"horizontal\":true},{\"icon\":\"fence\",\"x\":50,\"y\":50,\"amount\":10,\"horizontal\":true},{\"icon\":\"fence\",\"x\":250,\"y\":150,\"amount\":12,\"horizontal\":true},{\"icon\":\"fence\",\"x\":550,\"y\":350,\"amount\":12,\"horizontal\":true},{\"icon\":\"rock_large\",\"x\":400,\"y\":70,\"amount\":12,\"horizontal\":true},{\"icon\":\"rock_large\",\"x\":200,\"y\":200,\"amount\":6,\"horizontal\":false},{\"icon\":\"tree\",\"x\":5,\"y\":5,\"amount\":45,\"horizontal\":true},{\"icon\":\"tree\",\"x\":5,\"y\":5,\"amount\":20,\"horizontal\":false},{\"icon\":\"tree\",\"x\":22,\"y\":22,\"amount\":44,\"horizontal\":true},{\"icon\":\"tree\",\"x\":22,\"y\":22,\"amount\":20,\"horizontal\":false},{\"icon\":\"tree\",\"x\":5,\"y\":347,\"amount\":45,\"horizontal\":true},{\"icon\":\"tree\",\"x\":5,\"y\":364,\"amount\":45,\"horizontal\":true},{\"icon\":\"tree\",\"x\":735,\"y\":37,\"amount\":18,\"horizontal\":false},{\"icon\":\"tree\",\"x\":752,\"y\":37,\"amount\":18,\"horizontal\":false}],\"enemy_data\":[{\"id\":\"cyclops\",\"index\":0,\"start_position\":{\"x\":350,\"y\":210},\"end_position\":{\"x\":390,\"y\":210},\"move_timer\":2,\"speed\":30,\"attack_timer\":0.4,\"strength\":10,\"health\":100},{\"id\":\"ogre\",\"index\":1,\"start_position\":{\"x\":200,\"y\":320},\"end_position\":{\"x\":220,\"y\":320},\"move_timer\":0.5,\"speed\":45,\"attack_timer\":0.6,\"strength\":20,\"health\":200},{\"id\":\"ghost\",\"index\":2,\"start_position\":{\"x\":100,\"y\":80},\"end_position\":{\"x\":180,\"y\":85},\"move_timer\":2.2,\"speed\":55,\"attack_timer\":0.5,\"strength\":30,\"health\":300},{\"id\":\"ogre\",\"index\":3,\"start_position\":{\"x\":400,\"y\":50},\"end_position\":{\"x\":490,\"y\":50},\"move_timer\":1.7,\"speed\":35,\"attack_timer\":1.0,\"strength\":20,\"health\":200}],\"npc_data\":[{\"id\":\"naked\",\"index\":0,\"start_position\":{\"x\":350,\"y\":180},\"end_position\":{\"x\":350,\"y\":180},\"move_timer\":0,\"speed\":0}]}");
  92. if (!separate_world_data("shadow_woods_v5", json_data_str))
  93. {
  94. FURI_LOG_E("Game", "Failed to separate world data");
  95. }
  96. furi_string_free(json_data_str);
  97. set_world(level, manager, "shadow_woods_v5");
  98. /*
  99. adjust the player's position n such based on icon count
  100. the more icons to draw, the slower the player moves
  101. so we'll increase the player's speed as the icon count increases
  102. by 0.1 for every 8 icons
  103. */
  104. game_context->icon_offset = 0;
  105. if (!game_context->imu_present)
  106. {
  107. game_context->icon_offset += ((game_context->icon_count / 8) / 10);
  108. }
  109. player_spawn(level, manager);
  110. }
  111. static const LevelBehaviour _training_world = {
  112. .alloc = NULL,
  113. .free = NULL,
  114. .start = draw_town_world,
  115. .stop = NULL,
  116. .context_size = 0,
  117. };
  118. const LevelBehaviour *training_world()
  119. {
  120. return &_training_world;
  121. }
  122. FuriString *fetch_world(const char *name)
  123. {
  124. if (!name)
  125. {
  126. FURI_LOG_E("Game", "World name is NULL");
  127. return NULL;
  128. }
  129. FlipperHTTP *fhttp = flipper_http_alloc();
  130. if (!fhttp)
  131. {
  132. FURI_LOG_E("Game", "Failed to allocate HTTP");
  133. return NULL;
  134. }
  135. char url[256];
  136. snprintf(url, sizeof(url), "https://www.flipsocial.net/api/world/v5/get/world/%s/", name);
  137. snprintf(fhttp->file_path, sizeof(fhttp->file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/worlds/%s.json", name);
  138. fhttp->save_received_data = true;
  139. if (!flipper_http_get_request_with_headers(fhttp, url, "{\"Content-Type\": \"application/json\"}"))
  140. {
  141. FURI_LOG_E("Game", "Failed to send HTTP request");
  142. flipper_http_free(fhttp);
  143. return NULL;
  144. }
  145. fhttp->state = RECEIVING;
  146. furi_timer_start(fhttp->get_timeout_timer, TIMEOUT_DURATION_TICKS);
  147. while (fhttp->state == RECEIVING && furi_timer_is_running(fhttp->get_timeout_timer) > 0)
  148. {
  149. // Wait for the request to be received
  150. furi_delay_ms(100);
  151. }
  152. furi_timer_stop(fhttp->get_timeout_timer);
  153. if (fhttp->state != IDLE)
  154. {
  155. FURI_LOG_E("Game", "Failed to receive world data");
  156. flipper_http_free(fhttp);
  157. return NULL;
  158. }
  159. flipper_http_free(fhttp);
  160. FuriString *returned_data = load_furi_world(name);
  161. if (!returned_data)
  162. {
  163. FURI_LOG_E("Game", "Failed to load world data from file");
  164. return NULL;
  165. }
  166. if (!separate_world_data((char *)name, returned_data))
  167. {
  168. FURI_LOG_E("Game", "Failed to separate world data");
  169. furi_string_free(returned_data);
  170. return NULL;
  171. }
  172. return returned_data;
  173. }