world.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. #include <game/world.h>
  2. void draw_bounds(Canvas *canvas)
  3. {
  4. // Draw the outer bounds adjusted by camera offset
  5. // we draw this last to ensure users can see the bounds
  6. canvas_draw_frame(canvas, -camera_x, -camera_y, WORLD_WIDTH, WORLD_HEIGHT);
  7. }
  8. bool draw_json_world(Level *level, const char *json_data)
  9. {
  10. for (int i = 0; i < MAX_WORLD_OBJECTS; i++)
  11. {
  12. char *data = get_json_array_value("json_data", i, json_data);
  13. if (data == NULL)
  14. {
  15. break;
  16. }
  17. char *icon = get_json_value("icon", data);
  18. char *x = get_json_value("x", data);
  19. char *y = get_json_value("y", data);
  20. char *amount = get_json_value("amount", data);
  21. char *horizontal = get_json_value("horizontal", data);
  22. if (icon == NULL || x == NULL || y == NULL || amount == NULL || horizontal == NULL)
  23. {
  24. FURI_LOG_E("Failed Data: ", data);
  25. free(data);
  26. free(icon);
  27. free(x);
  28. free(y);
  29. free(amount);
  30. free(horizontal);
  31. level_clear(level);
  32. return false;
  33. }
  34. IconContext *icon_context = get_icon_context(icon);
  35. if (icon_context == NULL)
  36. {
  37. FURI_LOG_E("Failed Icon: ", icon);
  38. free(data);
  39. free(icon);
  40. free(x);
  41. free(y);
  42. free(amount);
  43. free(horizontal);
  44. level_clear(level);
  45. return false;
  46. }
  47. // if amount is less than 2, we spawn a single icon
  48. if (atoi(amount) < 2)
  49. {
  50. spawn_icon(level, icon_context->icon, atoi(x), atoi(y), icon_context->width, icon_context->height);
  51. free(data);
  52. free(icon);
  53. free(x);
  54. free(y);
  55. free(amount);
  56. free(horizontal);
  57. free(icon_context);
  58. continue;
  59. }
  60. spawn_icon_line(level, icon_context->icon, atoi(x), atoi(y), icon_context->width, icon_context->height, atoi(amount), strcmp(horizontal, "true") == 0);
  61. free(data);
  62. free(icon);
  63. free(x);
  64. free(y);
  65. free(amount);
  66. free(horizontal);
  67. free(icon_context);
  68. }
  69. return true;
  70. }
  71. bool draw_json_world_furi(Level *level, FuriString *json_data)
  72. {
  73. for (int i = 0; i < MAX_WORLD_OBJECTS; i++)
  74. {
  75. FuriString *data = get_json_array_value_furi("json_data", i, json_data);
  76. if (data == NULL)
  77. {
  78. break;
  79. }
  80. FuriString *icon = get_json_value_furi("icon", data);
  81. FuriString *x = get_json_value_furi("x", data);
  82. FuriString *y = get_json_value_furi("y", data);
  83. FuriString *amount = get_json_value_furi("amount", data);
  84. FuriString *horizontal = get_json_value_furi("horizontal", data);
  85. if (!icon || !x || !y || !amount || !horizontal)
  86. {
  87. FURI_LOG_E("Failed Data: ", furi_string_get_cstr(data));
  88. furi_string_free(data);
  89. furi_string_free(icon);
  90. furi_string_free(x);
  91. furi_string_free(y);
  92. furi_string_free(amount);
  93. furi_string_free(horizontal);
  94. level_clear(level);
  95. return false;
  96. }
  97. IconContext *icon_context = get_icon_context_furi(icon);
  98. if (icon_context == NULL)
  99. {
  100. FURI_LOG_E("Failed Icon: ", furi_string_get_cstr(icon));
  101. furi_string_free(data);
  102. furi_string_free(icon);
  103. furi_string_free(x);
  104. furi_string_free(y);
  105. furi_string_free(amount);
  106. furi_string_free(horizontal);
  107. level_clear(level);
  108. free(icon_context);
  109. return false;
  110. }
  111. // if amount is less than 2, we spawn a single icon
  112. if (atoi(furi_string_get_cstr(amount)) < 2)
  113. {
  114. spawn_icon(
  115. level,
  116. icon_context->icon,
  117. atoi(furi_string_get_cstr(x)),
  118. atoi(furi_string_get_cstr(y)),
  119. icon_context->width,
  120. icon_context->height);
  121. furi_string_free(data);
  122. furi_string_free(icon);
  123. furi_string_free(x);
  124. furi_string_free(y);
  125. furi_string_free(amount);
  126. furi_string_free(horizontal);
  127. free(icon_context);
  128. continue;
  129. }
  130. spawn_icon_line(
  131. level,
  132. icon_context->icon,
  133. atoi(furi_string_get_cstr(x)),
  134. atoi(furi_string_get_cstr(y)),
  135. icon_context->width,
  136. icon_context->height,
  137. atoi(furi_string_get_cstr(amount)),
  138. furi_string_cmp(horizontal, "true") == 0);
  139. furi_string_free(data);
  140. furi_string_free(icon);
  141. furi_string_free(x);
  142. furi_string_free(y);
  143. furi_string_free(amount);
  144. furi_string_free(horizontal);
  145. free(icon_context);
  146. }
  147. return true;
  148. }
  149. void draw_tree_world(Level *level)
  150. {
  151. IconContext *tree_icon = get_icon_context("tree");
  152. if (!tree_icon)
  153. {
  154. FURI_LOG_E("Game", "Failed to get tree icon context");
  155. return;
  156. }
  157. // Spawn two full left/up tree lines
  158. for (int i = 0; i < 2; i++)
  159. {
  160. // Horizontal line of 22 icons
  161. spawn_icon_line(level, tree_icon->icon, 5, 2 + i * 17, tree_icon->width, tree_icon->height, 22, true);
  162. // Vertical line of 11 icons
  163. spawn_icon_line(level, tree_icon->icon, 5 + i * 17, 2, tree_icon->width, tree_icon->height, 11, false);
  164. }
  165. // Spawn two full down tree lines
  166. for (int i = 9; i < 11; i++)
  167. {
  168. // Horizontal line of 22 icons
  169. spawn_icon_line(level, tree_icon->icon, 5, 2 + i * 17, tree_icon->width, tree_icon->height, 22, true);
  170. }
  171. // Spawn two full right tree lines
  172. for (int i = 20; i < 22; i++)
  173. {
  174. // Vertical line of 8 icons starting further down (y=50)
  175. spawn_icon_line(level, tree_icon->icon, 5 + i * 17, 50, tree_icon->width, tree_icon->height, 8, false);
  176. }
  177. // Labyrinth lines
  178. // Third line (14 left, then a gap, then 3 middle)
  179. spawn_icon_line(level, tree_icon->icon, 5, 2 + 2 * 17, tree_icon->width, tree_icon->height, 14, true);
  180. spawn_icon_line(level, tree_icon->icon, 5 + 16 * 17, 2 + 2 * 17, tree_icon->width, tree_icon->height, 3, true);
  181. // Fourth line (3 left, 6 middle, 4 right)
  182. spawn_icon_line(level, tree_icon->icon, 5, 2 + 3 * 17, tree_icon->width, tree_icon->height, 3, true); // 3 left
  183. spawn_icon_line(level, tree_icon->icon, 5 + 7 * 17, 2 + 3 * 17, tree_icon->width, tree_icon->height, 6, true); // 6 middle
  184. spawn_icon_line(level, tree_icon->icon, 5 + 15 * 17, 2 + 3 * 17, tree_icon->width, tree_icon->height, 4, true); // 4 right
  185. // Fifth line (6 left, 7 middle)
  186. spawn_icon_line(level, tree_icon->icon, 5, 2 + 4 * 17, tree_icon->width, tree_icon->height, 6, true);
  187. spawn_icon_line(level, tree_icon->icon, 5 + 7 * 17, 2 + 4 * 17, tree_icon->width, tree_icon->height, 7, true);
  188. // Sixth line (5 left, 3 middle, 7 right)
  189. spawn_icon_line(level, tree_icon->icon, 5, 2 + 5 * 17, tree_icon->width, tree_icon->height, 5, true); // 5 left
  190. spawn_icon_line(level, tree_icon->icon, 5 + 7 * 17, 2 + 5 * 17, tree_icon->width, tree_icon->height, 3, true); // 3 middle
  191. spawn_icon_line(level, tree_icon->icon, 5 + 15 * 17, 2 + 5 * 17, tree_icon->width, tree_icon->height, 7, true); // 7 right
  192. // Seventh line (0 left, 7 middle, 4 right)
  193. spawn_icon_line(level, tree_icon->icon, 5 + 6 * 17, 2 + 6 * 17, tree_icon->width, tree_icon->height, 7, true); // 7 middle
  194. spawn_icon_line(level, tree_icon->icon, 5 + 14 * 17, 2 + 6 * 17, tree_icon->width, tree_icon->height, 4, true); // 4 right
  195. // Eighth line (4 left, 3 middle, 4 right)
  196. spawn_icon_line(level, tree_icon->icon, 5, 2 + 7 * 17, tree_icon->width, tree_icon->height, 4, true); // 4 left
  197. spawn_icon_line(level, tree_icon->icon, 5 + 7 * 17, 2 + 7 * 17, tree_icon->width, tree_icon->height, 3, true); // 3 middle
  198. spawn_icon_line(level, tree_icon->icon, 5 + 15 * 17, 2 + 7 * 17, tree_icon->width, tree_icon->height, 4, true); // 4 right
  199. // Ninth line (3 left, 1 middle, 3 right)
  200. spawn_icon_line(level, tree_icon->icon, 5, 2 + 8 * 17, tree_icon->width, tree_icon->height, 3, true); // 3 left
  201. spawn_icon_line(level, tree_icon->icon, 5 + 5 * 17, 2 + 8 * 17, tree_icon->width, tree_icon->height, 1, true); // 1 middle
  202. spawn_icon_line(level, tree_icon->icon, 5 + 11 * 17, 2 + 8 * 17, tree_icon->width, tree_icon->height, 3, true); // 3 right
  203. free(tree_icon);
  204. }
  205. void draw_town_world(Level *level)
  206. {
  207. // define all the icons
  208. IconContext *house_icon = get_icon_context("house");
  209. IconContext *fence_icon = get_icon_context("fence");
  210. IconContext *fence_end_icon = get_icon_context("fence_end");
  211. IconContext *plant_icon = get_icon_context("plant");
  212. IconContext *flower_icon = get_icon_context("flower");
  213. IconContext *man_icon = get_icon_context("man");
  214. IconContext *woman_icon = get_icon_context("woman");
  215. IconContext *lake_top_left_icon = get_icon_context("lake_top_left");
  216. IconContext *lake_top_icon = get_icon_context("lake_top");
  217. IconContext *lake_top_right_icon = get_icon_context("lake_top_right");
  218. IconContext *lake_left_icon = get_icon_context("lake_left");
  219. IconContext *lake_right_icon = get_icon_context("lake_right");
  220. IconContext *lake_bottom_left_icon = get_icon_context("lake_bottom_left");
  221. IconContext *lake_bottom_icon = get_icon_context("lake_bottom");
  222. IconContext *lake_bottom_right_icon = get_icon_context("lake_bottom_right");
  223. IconContext *tree_icon = get_icon_context("tree");
  224. // check if any of the icons are NULL
  225. if (!house_icon || !fence_icon || !fence_end_icon || !plant_icon || !flower_icon ||
  226. !man_icon || !woman_icon || !lake_top_left_icon || !lake_top_icon || !lake_top_right_icon ||
  227. !lake_left_icon || !lake_right_icon || !lake_bottom_left_icon || !lake_bottom_icon || !lake_bottom_right_icon || !tree_icon)
  228. {
  229. FURI_LOG_E("Game", "Failed to get icon context");
  230. return;
  231. }
  232. // house-fence group 1
  233. spawn_icon(level, house_icon->icon, 148, 36, house_icon->width, house_icon->height);
  234. spawn_icon(level, fence_icon->icon, 148, 72, fence_icon->width, fence_icon->height);
  235. spawn_icon(level, fence_icon->icon, 164, 72, fence_icon->width, fence_icon->height);
  236. spawn_icon(level, fence_end_icon->icon, 180, 72, fence_end_icon->width, fence_end_icon->height);
  237. // house-fence group 4 (the left of group 1)
  238. spawn_icon(level, house_icon->icon, 96, 36, house_icon->width, house_icon->height);
  239. spawn_icon(level, fence_icon->icon, 96, 72, fence_icon->width, fence_icon->height);
  240. spawn_icon(level, fence_icon->icon, 110, 72, fence_icon->width, fence_icon->height);
  241. spawn_icon(level, fence_end_icon->icon, 126, 72, fence_end_icon->width, fence_end_icon->height);
  242. // house-fence group 5 (the left of group 4)
  243. spawn_icon(level, house_icon->icon, 40, 36, house_icon->width, house_icon->height);
  244. spawn_icon(level, fence_icon->icon, 40, 72, fence_icon->width, fence_icon->height);
  245. spawn_icon(level, fence_icon->icon, 56, 72, fence_icon->width, fence_icon->height);
  246. spawn_icon(level, fence_end_icon->icon, 72, 72, fence_end_icon->width, fence_end_icon->height);
  247. // line of fences on the 8th row (using spawn_icon_line)
  248. spawn_icon_line(level, fence_icon->icon, 8, 100, fence_icon->width, fence_icon->height, 10, true);
  249. // plants spaced out underneath the fences
  250. spawn_icon_line(level, plant_icon->icon, 40, 110, plant_icon->width, plant_icon->height, 6, true);
  251. spawn_icon_line(level, flower_icon->icon, 40, 140, flower_icon->width, flower_icon->height, 6, true);
  252. // man and woman
  253. spawn_icon(level, man_icon->icon, 156, 110, man_icon->width, man_icon->height);
  254. spawn_icon(level, woman_icon->icon, 164, 110, woman_icon->width, woman_icon->height);
  255. // lake
  256. // Top row
  257. spawn_icon(level, lake_top_left_icon->icon, 240, 52, lake_top_left_icon->width, lake_top_left_icon->height);
  258. spawn_icon(level, lake_top_icon->icon, 264, 52, lake_top_icon->width, lake_top_icon->height);
  259. spawn_icon(level, lake_top_right_icon->icon, 295, 52, lake_top_right_icon->width, lake_top_right_icon->height);
  260. // Middle row
  261. spawn_icon(level, lake_left_icon->icon, 231, 74, lake_left_icon->width, lake_left_icon->height);
  262. spawn_icon(level, lake_right_icon->icon, 317, 74, lake_right_icon->width, lake_right_icon->height);
  263. // Bottom row
  264. spawn_icon(level, lake_bottom_left_icon->icon, 240, 105, lake_bottom_left_icon->width, lake_bottom_left_icon->height);
  265. spawn_icon(level, lake_bottom_icon->icon, 264, 124, lake_bottom_icon->width, lake_bottom_icon->height);
  266. spawn_icon(level, lake_bottom_right_icon->icon, 295, 105, lake_bottom_right_icon->width, lake_bottom_right_icon->height);
  267. // Spawn two full left/up tree lines
  268. for (int i = 0; i < 2; i++)
  269. {
  270. // Horizontal line of 22 icons
  271. spawn_icon_line(level, tree_icon->icon, 5, 2 + i * 17, tree_icon->width, tree_icon->height, 22, true);
  272. // Vertical line of 11 icons
  273. spawn_icon_line(level, tree_icon->icon, 5 + i * 17, 2, tree_icon->width, tree_icon->height, 11, false);
  274. }
  275. // Spawn two full down tree lines
  276. for (int i = 9; i < 11; i++)
  277. {
  278. // Horizontal line of 22 icons
  279. spawn_icon_line(level, tree_icon->icon, 5, 2 + i * 17, tree_icon->width, tree_icon->height, 22, true);
  280. }
  281. // Spawn two full right tree lines
  282. for (int i = 20; i < 22; i++)
  283. {
  284. // Vertical line of 8 icons starting further down (y=50)
  285. spawn_icon_line(level, tree_icon->icon, 5 + i * 17, 50, tree_icon->width, tree_icon->height, 8, false);
  286. }
  287. free(house_icon);
  288. free(fence_icon);
  289. free(fence_end_icon);
  290. free(plant_icon);
  291. free(flower_icon);
  292. free(man_icon);
  293. free(woman_icon);
  294. free(lake_top_left_icon);
  295. free(lake_top_icon);
  296. free(lake_top_right_icon);
  297. free(lake_left_icon);
  298. free(lake_right_icon);
  299. free(lake_bottom_left_icon);
  300. free(lake_bottom_icon);
  301. free(lake_bottom_right_icon);
  302. free(tree_icon);
  303. }
  304. FuriString *fetch_world(char *name, void *app)
  305. {
  306. if (!app || !name)
  307. {
  308. FURI_LOG_E("Game", "App or name is NULL");
  309. return NULL;
  310. }
  311. if (!flipper_http_init(flipper_http_rx_callback, app))
  312. {
  313. FURI_LOG_E("Game", "Failed to initialize HTTP");
  314. return NULL;
  315. }
  316. char url[256];
  317. snprintf(url, sizeof(url), "https://www.flipsocial.net/api/world/get/world/%s/", name);
  318. snprintf(fhttp.file_path, sizeof(fhttp.file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/worlds/%s.json", name);
  319. fhttp.save_received_data = true;
  320. if (!flipper_http_get_request_with_headers(url, "{\"Content-Type\": \"application/json\"}"))
  321. {
  322. FURI_LOG_E("Game", "Failed to send HTTP request");
  323. return NULL;
  324. }
  325. furi_timer_start(fhttp.get_timeout_timer, TIMEOUT_DURATION_TICKS);
  326. while (fhttp.state == RECEIVING && furi_timer_is_running(fhttp.get_timeout_timer) > 0)
  327. {
  328. // Wait for the request to be received
  329. furi_delay_ms(100);
  330. }
  331. furi_timer_stop(fhttp.get_timeout_timer);
  332. if (fhttp.state != IDLE)
  333. {
  334. FURI_LOG_E("Game", "Failed to receive world data");
  335. return NULL;
  336. }
  337. FuriString *returned_data = flipper_http_load_from_file(fhttp.file_path);
  338. if (!returned_data)
  339. {
  340. FURI_LOG_E("Game", "Failed to load world data from file");
  341. return NULL;
  342. }
  343. return returned_data;
  344. }