world.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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\":\"funny\",\"index\":0,\"start_position\":{\"x\":350,\"y\":180},\"end_position\":{\"x\":350,\"y\":180},\"move_timer\":0,\"speed\":0,\"message\":\"Hello there!\"}]}");
  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. game_context->icon_offset = 0;
  99. if (!game_context->imu_present)
  100. {
  101. game_context->icon_offset += ((game_context->icon_count / 10) / 15);
  102. }
  103. player_spawn(level, manager);
  104. }
  105. static const LevelBehaviour _training_world = {
  106. .alloc = NULL,
  107. .free = NULL,
  108. .start = draw_town_world,
  109. .stop = NULL,
  110. .context_size = 0,
  111. };
  112. const LevelBehaviour *training_world()
  113. {
  114. return &_training_world;
  115. }
  116. static void draw_pvp_world(Level *level, GameManager *manager, void *context)
  117. {
  118. UNUSED(context);
  119. if (!manager || !level)
  120. {
  121. FURI_LOG_E("Game", "Manager or level is NULL");
  122. return;
  123. }
  124. GameContext *game_context = game_manager_game_context_get(manager);
  125. level_clear(level);
  126. FuriString *json_data_str = furi_string_alloc();
  127. furi_string_cat_str(json_data_str, "{\"name\":\"pvp_world\",\"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}]}");
  128. if (!separate_world_data("pvp_world", json_data_str))
  129. {
  130. FURI_LOG_E("Game", "Failed to separate world data");
  131. }
  132. furi_string_free(json_data_str);
  133. set_world(level, manager, "pvp_world");
  134. game_context->icon_offset = 0;
  135. if (!game_context->imu_present)
  136. {
  137. game_context->icon_offset += ((game_context->icon_count / 10) / 15);
  138. }
  139. player_spawn(level, manager);
  140. }
  141. static const LevelBehaviour _pvp_world = {
  142. .alloc = NULL,
  143. .free = NULL,
  144. .start = draw_pvp_world,
  145. .stop = NULL,
  146. .context_size = 0,
  147. };
  148. const LevelBehaviour *pvp_world()
  149. {
  150. return &_pvp_world;
  151. }
  152. FuriString *fetch_world(const char *name)
  153. {
  154. if (!name)
  155. {
  156. FURI_LOG_E("Game", "World name is NULL");
  157. return NULL;
  158. }
  159. FlipperHTTP *fhttp = flipper_http_alloc();
  160. if (!fhttp)
  161. {
  162. FURI_LOG_E("Game", "Failed to allocate HTTP");
  163. return NULL;
  164. }
  165. char url[256];
  166. snprintf(url, sizeof(url), "https://www.jblanked.com/flipper/api/world/v5/get/world/%s/", name);
  167. snprintf(fhttp->file_path, sizeof(fhttp->file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/worlds/%s.json", name);
  168. fhttp->save_received_data = true;
  169. if (!flipper_http_request(fhttp, GET, url, "{\"Content-Type\": \"application/json\"}", NULL))
  170. {
  171. FURI_LOG_E("Game", "Failed to send HTTP request");
  172. flipper_http_free(fhttp);
  173. return NULL;
  174. }
  175. fhttp->state = RECEIVING;
  176. furi_timer_start(fhttp->get_timeout_timer, TIMEOUT_DURATION_TICKS);
  177. while (fhttp->state == RECEIVING && furi_timer_is_running(fhttp->get_timeout_timer) > 0)
  178. {
  179. // Wait for the request to be received
  180. furi_delay_ms(100);
  181. }
  182. furi_timer_stop(fhttp->get_timeout_timer);
  183. if (fhttp->state != IDLE)
  184. {
  185. FURI_LOG_E("Game", "Failed to receive world data");
  186. flipper_http_free(fhttp);
  187. return NULL;
  188. }
  189. flipper_http_free(fhttp);
  190. FuriString *returned_data = load_furi_world(name);
  191. if (!returned_data)
  192. {
  193. FURI_LOG_E("Game", "Failed to load world data from file");
  194. return NULL;
  195. }
  196. if (!separate_world_data((char *)name, returned_data))
  197. {
  198. FURI_LOG_E("Game", "Failed to separate world data");
  199. furi_string_free(returned_data);
  200. return NULL;
  201. }
  202. return returned_data;
  203. }