PageRenderTime 46ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/freedroidrpg-0.15.1/src/misc.c

#
C | 1337 lines | 801 code | 201 blank | 335 comment | 114 complexity | da626b81ffab2e0e5b7eca2fa35e69e0 MD5 | raw file
Possible License(s): AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. *
  3. * Copyright (c) 1994, 2002, 2003 Johannes Prix
  4. * Copyright (c) 1994, 2002 Reinhard Prix
  5. * Copyright (c) 2004-2010 Arthur Huillet
  6. *
  7. *
  8. * This file is part of Freedroid
  9. *
  10. * Freedroid is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * Freedroid is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with Freedroid; see the file COPYING. If not, write to the
  22. * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23. * MA 02111-1307 USA
  24. *
  25. */
  26. /**
  27. * This file contains miscellaeous helpful functions for FreedroidRPG.
  28. */
  29. #define _misc_c
  30. #include "system.h"
  31. #include "defs.h"
  32. #include "struct.h"
  33. #include "global.h"
  34. #include "proto.h"
  35. #include "savestruct.h"
  36. //--------------------
  37. // This header file is needed
  38. #if HAVE_EXECINFO_H
  39. # include <execinfo.h>
  40. #endif
  41. #if HAVE_SIGNAL_H
  42. # include <signal.h>
  43. #endif
  44. static int world_is_frozen = 0;
  45. long oneframedelay = 0;
  46. long tenframedelay = 0;
  47. long onehundredframedelay = 0;
  48. float FPSover1 = 10;
  49. float FPSover10 = 10;
  50. float FPSover100 = 10;
  51. Uint32 Now_SDL_Ticks;
  52. Uint32 One_Frame_SDL_Ticks;
  53. Uint32 Ten_Frame_SDL_Ticks;
  54. Uint32 Onehundred_Frame_SDL_Ticks;
  55. int framenr = 0;
  56. long Overall_Frames_Displayed = 0;
  57. char *our_homedir = NULL;
  58. char *our_config_dir = NULL;
  59. mouse_press_button AllMousePressButtons[MAX_MOUSE_PRESS_BUTTONS] = {
  60. [UP_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/UpButton.png", {600, 94, 40, 40}, TRUE},
  61. [DOWN_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/DownButton.png", {600, 316, 40, 40}, TRUE},
  62. [ITEM_BROWSER_LEFT_BUTTON] = {EMPTY_IMAGE, "THIS_DOESNT_NEED_BLITTING", {280, 44, 37, 37}, TRUE},
  63. [ITEM_BROWSER_RIGHT_BUTTON] = {EMPTY_IMAGE, "THIS_DOESNT_NEED_BLITTING", {536, 44, 37, 37}, TRUE},
  64. [ITEM_BROWSER_EXIT_BUTTON] = {EMPTY_IMAGE, "THIS_DOESNT_NEED_BLITTING", {201, 340, 47, 47}, TRUE},
  65. [LEFT_SHOP_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/LeftButton.png", {23, 446, 23, 23}, TRUE},
  66. [RIGHT_SHOP_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/RightButton.png", {580, 447, 23, 23}, TRUE},
  67. [LEFT_TUX_SHOP_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/LeftShopButton.png", {6, 15, 23, 23}, TRUE},
  68. [RIGHT_TUX_SHOP_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/RightShopButton.png", {584, 15, 23, 23}, TRUE},
  69. [LEFT_LEVEL_EDITOR_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/LevelEditorObjectSelectorLeft.png", {3, 8, 15, 60}, FALSE},
  70. [LEFT_LEVEL_EDITOR_BUTTON_PUSHED] =
  71. {EMPTY_IMAGE, "mouse_buttons/LevelEditorObjectSelectorLeftPushed.png", {2, 7, 15, 60}, FALSE},
  72. [RIGHT_LEVEL_EDITOR_BUTTON] =
  73. {EMPTY_IMAGE, "mouse_buttons/LevelEditorObjectSelectorRight.png", {-16, 8, 15, 60}, FALSE},
  74. [RIGHT_LEVEL_EDITOR_BUTTON_PUSHED] =
  75. {EMPTY_IMAGE, "mouse_buttons/LevelEditorObjectSelectorRightPushed.png", {-17, 7, 15, 60}, FALSE},
  76. [NUMBER_SELECTOR_OK_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/number_selector_ok_button.png", {308, 288, 48, 48}, TRUE},
  77. [NUMBER_SELECTOR_LEFT_BUTTON] = {EMPTY_IMAGE, "THIS_DOESNT_NEED_BLITTING", {148, 244, 35, 35}, TRUE},
  78. [NUMBER_SELECTOR_RIGHT_BUTTON] = {EMPTY_IMAGE, "THIS_DOESNT_NEED_BLITTING", {404, 244, 35, 35}, TRUE},
  79. [BUY_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/buy_button.png", {199, 98, 47, 47}, TRUE},
  80. [SELL_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/sell_button.png", {199, 153, 47, 47}, TRUE},
  81. [REPAIR_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/repair_button.png", {199, 225, 47, 47}, TRUE},
  82. [OPEN_CLOSE_SKILL_EXPLANATION_BUTTON] = {EMPTY_IMAGE, "THIS_DOESNT_NEED_BLITTING", {0 + 17, 424, 33, 33}, FALSE},
  83. /* lower right area next to the mini map*/
  84. [LEVEL_EDITOR_DELETE_OBSTACLE_BUTTON] =
  85. {EMPTY_IMAGE, "mouse_buttons/LevelEditorDeleteObstacleButton.png", {-270, -30, 0, 0}, FALSE},
  86. [LEVEL_EDITOR_DELETE_OBSTACLE_BUTTON_PUSHED] =
  87. {EMPTY_IMAGE, "mouse_buttons/LevelEditorDeleteObstacleButtonPushed.png", {-271, -31, 0, 0}, FALSE},
  88. [LEVEL_EDITOR_NEXT_OBJECT_BUTTON] =
  89. {EMPTY_IMAGE, "mouse_buttons/LevelEditorNextObstacleButton.png", {-240, -30, 0, 0}, FALSE},
  90. [LEVEL_EDITOR_NEXT_OBJECT_BUTTON_PUSHED] =
  91. {EMPTY_IMAGE, "mouse_buttons/LevelEditorNextObstacleButtonPushed.png", {-241, -31, 0, 0}, FALSE},
  92. /* upper right are directly under the object selector*/
  93. [LEVEL_EDITOR_SAVE_SHIP_BUTTON] =
  94. {EMPTY_IMAGE, "mouse_buttons/LevelEditorSaveShipButton.png", {-60, 80, 0, 0}, FALSE},
  95. [LEVEL_EDITOR_SAVE_SHIP_BUTTON_PUSHED] =
  96. {EMPTY_IMAGE, "mouse_buttons/LevelEditorSaveShipButtonPushed.png", {-59, 79, 0, 0}, FALSE},
  97. [LEVEL_EDITOR_SAVE_SHIP_BUTTON_OFF] =
  98. {EMPTY_IMAGE, "mouse_buttons/LevelEditorSaveShipButtonOff.png", {-60, 80, 0, 0}, FALSE},
  99. [LEVEL_EDITOR_SAVE_SHIP_BUTTON_OFF_PUSHED] =
  100. {EMPTY_IMAGE, "mouse_buttons/LevelEditorSaveShipButtonOffPushed.png", {-59, 79, 0, 0}, FALSE},
  101. [LEVEL_EDITOR_QUIT_BUTTON] =
  102. {EMPTY_IMAGE, "mouse_buttons/LevelEditorQuitButton.png", {-30, 80, 0, 0}, FALSE},
  103. [LEVEL_EDITOR_QUIT_BUTTON_PUSHED] =
  104. {EMPTY_IMAGE, "mouse_buttons/LevelEditorQuitButtonPushed.png", {-29, 79, 0, 0}, FALSE},
  105. /* above the obstacle selectors, upper row */
  106. [LEVEL_EDITOR_EDIT_CHEST_BUTTON] =
  107. {EMPTY_IMAGE, "mouse_buttons/LevelEditorEditChestButton.png", {-150, -350, 0, 0}, FALSE},
  108. [LEVEL_EDITOR_EDIT_CHEST_BUTTON_PUSHED] =
  109. {EMPTY_IMAGE, "mouse_buttons/LevelEditorEditChestButtonPushed.png", {-149, -349, 0, 0}, FALSE},
  110. [LEVEL_EDITOR_NEW_OBSTACLE_LABEL_BUTTON] =
  111. {EMPTY_IMAGE, "mouse_buttons/LevelEditorNewObstacleLabelButton.png", {-120, -350, 0, 0}, FALSE},
  112. [LEVEL_EDITOR_NEW_OBSTACLE_LABEL_BUTTON_PUSHED] =
  113. {EMPTY_IMAGE, "mouse_buttons/LevelEditorNewObstacleLabelButtonPushed.png", {-119, -349, 0, 0}, FALSE},
  114. [LEVEL_EDITOR_TOGGLE_WAYPOINT_CONNECTIONS_BUTTON] =
  115. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleWaypointConnectionsButton.png", {-90, -350, 0, 0}, FALSE},
  116. [LEVEL_EDITOR_TOGGLE_WAYPOINT_CONNECTIONS_BUTTON_PUSHED] =
  117. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleWaypointConnectionsButtonPushed.png", {-90, -350, 0, 0}, FALSE},
  118. [LEVEL_EDITOR_TOGGLE_WAYPOINT_CONNECTIONS_BUTTON_OFF] =
  119. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleWaypointConnectionsButtonOff.png", {-90, -350, 0, 0}, FALSE},
  120. [LEVEL_EDITOR_TOGGLE_WAYPOINT_CONNECTIONS_BUTTON_OFF_PUSHED] =
  121. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleWaypointConnectionsButtonOffPushed.png", {-90, -350, 0, 0}, FALSE},
  122. [LEVEL_EDITOR_ZOOM_IN_BUTTON] =
  123. {EMPTY_IMAGE, "mouse_buttons/LevelEditorZoomInButton.png", {-60, -350, 0, 0}, FALSE},
  124. [LEVEL_EDITOR_ZOOM_IN_BUTTON_PUSHED] =
  125. {EMPTY_IMAGE, "mouse_buttons/LevelEditorZoomInButtonPushed.png", {-59, -349, 0, 0}, FALSE},
  126. [LEVEL_EDITOR_ZOOM_OUT_BUTTON] =
  127. {EMPTY_IMAGE, "mouse_buttons/LevelEditorZoomOutButton.png", {-60, -350, 0, 0}, FALSE},
  128. [LEVEL_EDITOR_ZOOM_OUT_BUTTON_PUSHED] =
  129. {EMPTY_IMAGE, "mouse_buttons/LevelEditorZoomOutButtonPushed.png", {-59, -349, 0, 0}, FALSE},
  130. [LEVEL_EDITOR_BEAUTIFY_GRASS_BUTTON] =
  131. {EMPTY_IMAGE, "mouse_buttons/LevelEditorBeautifyGrassButton.png", {-30, -350, 0, 0}, FALSE},
  132. [LEVEL_EDITOR_BEAUTIFY_GRASS_BUTTON_PUSHED] =
  133. {EMPTY_IMAGE, "mouse_buttons/LevelEditorBeautifyGrassButtonPushed.png", {-29, -349, 0, 0}, FALSE},
  134. [LEVEL_EDITOR_ALL_FLOOR_LAYERS_BUTTON] =
  135. {EMPTY_IMAGE, "mouse_buttons/LevelEditorAllFloorLayersButton.png", {-120, -350, 0, 0}, FALSE},
  136. [LEVEL_EDITOR_ALL_FLOOR_LAYERS_BUTTON_PUSHED] =
  137. {EMPTY_IMAGE, "mouse_buttons/LevelEditorAllFloorLayersButtonPushed.png", {-120, -350, 0, 0}, FALSE},
  138. [LEVEL_EDITOR_SINGLE_FLOOR_LAYER_BUTTON] =
  139. {EMPTY_IMAGE, "mouse_buttons/LevelEditorSingleFloorLayerButton.png", {-120, -350, 0, 0}, FALSE},
  140. [LEVEL_EDITOR_SINGLE_FLOOR_LAYER_BUTTON_PUSHED] =
  141. {EMPTY_IMAGE, "mouse_buttons/LevelEditorSingleFloorLayerButtonPushed.png", {-120, -350, 0, 0}, FALSE},
  142. /* above the obstacle selector, lower row*/
  143. [LEVEL_EDITOR_TOGGLE_GRID_BUTTON_OFF] =
  144. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleGridButtonOff.png", {-150, -320, 0, 0}, FALSE},
  145. [LEVEL_EDITOR_TOGGLE_GRID_BUTTON_OFF_PUSHED] =
  146. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleGridButtonOffPushed.png", {-149, -319, 0, 0}, FALSE},
  147. [LEVEL_EDITOR_TOGGLE_GRID_BUTTON] =
  148. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleGridButton.png", {-150, -320, 0, 0}, FALSE},
  149. [LEVEL_EDITOR_TOGGLE_GRID_BUTTON_PUSHED] =
  150. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleGridButtonPushed.png", {-149, -319, 0, 0}, FALSE},
  151. [LEVEL_EDITOR_TOGGLE_GRID_BUTTON_FULL] =
  152. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleGridButtonFull.png", {-150, -320, 0, 0}, FALSE},
  153. [LEVEL_EDITOR_TOGGLE_GRID_BUTTON_FULL_PUSHED] =
  154. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleGridButtonFullPushed.png", {-149, -319, 0, 0}, FALSE},
  155. [LEVEL_EDITOR_TOGGLE_ENEMIES_BUTTON] =
  156. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleEnemiesButton.png", {-120, -320, 0, 0}, FALSE},
  157. [LEVEL_EDITOR_TOGGLE_ENEMIES_BUTTON_PUSHED] =
  158. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleEnemiesButtonPushed.png", {-119, -319, 0, 0}, FALSE},
  159. [LEVEL_EDITOR_TOGGLE_ENEMIES_BUTTON_OFF] =
  160. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleEnemiesButtonOff.png", {-120, -320, 0, 0}, FALSE},
  161. [LEVEL_EDITOR_TOGGLE_ENEMIES_BUTTON_OFF_PUSHED] =
  162. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleEnemiesButtonOffPushed.png", {-119, -319, 0, 0}, FALSE},
  163. [LEVEL_EDITOR_TOGGLE_OBSTACLES_BUTTON] =
  164. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleObstaclesButton.png", {-90, -320, 0, 0}, FALSE},
  165. [LEVEL_EDITOR_TOGGLE_OBSTACLES_BUTTON_PUSHED] =
  166. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleObstaclesButtonPushed.png", {-89, -319, 0, 0}, FALSE},
  167. [LEVEL_EDITOR_TOGGLE_OBSTACLES_BUTTON_OFF] =
  168. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleObstaclesButtonOff.png", {-90, -320, 0, 0}, FALSE},
  169. [LEVEL_EDITOR_TOGGLE_OBSTACLES_BUTTON_OFF_PUSHED] =
  170. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleObstaclesButtonOffPushed.png", {-89, -319, 0, 0}, FALSE},
  171. [LEVEL_EDITOR_TOGGLE_TOOLTIPS_BUTTON] =
  172. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleTooltipsButton.png", {-60, -320, 0, 0}, FALSE},
  173. [LEVEL_EDITOR_TOGGLE_TOOLTIPS_BUTTON_PUSHED] =
  174. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleTooltipsButtonPushed.png", {-59, -319, 0, 0}, FALSE},
  175. [LEVEL_EDITOR_TOGGLE_TOOLTIPS_BUTTON_OFF] =
  176. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleTooltipsButtonOff.png", {-60, -320, 0, 0}, FALSE},
  177. [LEVEL_EDITOR_TOGGLE_TOOLTIPS_BUTTON_OFF_PUSHED] =
  178. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleTooltipsButtonOffPushed.png", {-59, -319, 0, 0}, FALSE},
  179. [LEVEL_EDITOR_TOGGLE_COLLISION_RECTS_BUTTON] =
  180. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleCollisionRectsButton.png", {-30, -320, 0, 0}, FALSE},
  181. [LEVEL_EDITOR_TOGGLE_COLLISION_RECTS_BUTTON_PUSHED] =
  182. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleCollisionRectsButtonPushed.png", {-29, -319, 0, 0}, FALSE},
  183. [LEVEL_EDITOR_TOGGLE_COLLISION_RECTS_BUTTON_OFF] =
  184. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleCollisionRectsButtonOff.png", {-30, -320, 0, 0}, FALSE},
  185. [LEVEL_EDITOR_TOGGLE_COLLISION_RECTS_BUTTON_OFF_PUSHED] =
  186. {EMPTY_IMAGE, "mouse_buttons/LevelEditorToggleCollisionRectsButtonOffPushed.png", {-29, -319, 0, 0}, FALSE},
  187. [LEVEL_EDITOR_NEXT_ITEM_GROUP_BUTTON] =
  188. {EMPTY_IMAGE, "mouse_buttons/RightButton.png", {55 + 64 * 8, 32 + 5 * 66, 0, 0}, TRUE},
  189. [LEVEL_EDITOR_PREV_ITEM_GROUP_BUTTON] =
  190. {EMPTY_IMAGE, "mouse_buttons/LeftButton.png", {55, 32 + 5 * 66, 0, 0}, TRUE},
  191. [LEVEL_EDITOR_CANCEL_ITEM_DROP_BUTTON] =
  192. {EMPTY_IMAGE, "mouse_buttons/LevelEditorCancelItemDrop.png", {55 + 80, 32 + 5 * 66, 0, 0}, TRUE},
  193. [LEVEL_EDITOR_UNDO_BUTTON] =
  194. {EMPTY_IMAGE, "mouse_buttons/LevelEditorUndoButton.png", {-330, -30, 0, 0}, FALSE},
  195. [LEVEL_EDITOR_UNDO_BUTTON_PUSHED] =
  196. {EMPTY_IMAGE, "mouse_buttons/LevelEditorUndoButtonPushed.png", {-331, -31, 0, 0}, FALSE},
  197. [LEVEL_EDITOR_REDO_BUTTON] =
  198. {EMPTY_IMAGE, "mouse_buttons/LevelEditorRedoButton.png", {-300, -30, 0, 0}, FALSE},
  199. [LEVEL_EDITOR_REDO_BUTTON_PUSHED] =
  200. {EMPTY_IMAGE, "mouse_buttons/LevelEditorRedoButtonPushed.png", {-301, -31, 0, 0}, FALSE},
  201. [LEVEL_EDITOR_TYPESELECT_OBSTACLE_BUTTON] =
  202. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton.png", {-152, -290, 0, 0}, FALSE},
  203. [LEVEL_EDITOR_TYPESELECT_OBSTACLE_BUTTON_PUSHED] =
  204. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButtonPushed.png", {-152, -290, 0, 0}, FALSE},
  205. [LEVEL_EDITOR_TYPESELECT_OBSTACLE_BUTTON_OFF] =
  206. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButtonOff.png", {-152, -290, 0, 0}, FALSE},
  207. [LEVEL_EDITOR_TYPESELECT_OBSTACLE_BUTTON_OFF_PUSHED] =
  208. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButtonOffPushed.png", {-152, -290, 0, 0}, FALSE},
  209. [LEVEL_EDITOR_TYPESELECT_ENEMY_BUTTON] =
  210. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton3.png", {-90, -214, 0, 0}, FALSE},
  211. [LEVEL_EDITOR_TYPESELECT_ENEMY_BUTTON_PUSHED] =
  212. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton3Pushed.png", {-90, -214, 0, 0}, FALSE},
  213. [LEVEL_EDITOR_TYPESELECT_ENEMY_BUTTON_OFF] =
  214. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton3Off.png", {-90, -214, 0, 0}, FALSE},
  215. [LEVEL_EDITOR_TYPESELECT_ENEMY_BUTTON_OFF_PUSHED] =
  216. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton3OffPushed.png", {-90, -214, 0, 0}, FALSE},
  217. [LEVEL_EDITOR_TYPESELECT_FLOOR_BUTTON] =
  218. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton.png", {-152, -252, 0, 0}, FALSE},
  219. [LEVEL_EDITOR_TYPESELECT_FLOOR_BUTTON_PUSHED] =
  220. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButtonPushed.png", {-152, -252, 0, 0}, FALSE},
  221. [LEVEL_EDITOR_TYPESELECT_FLOOR_BUTTON_OFF] =
  222. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButtonOff.png", {-152, -252, 0, 0}, FALSE},
  223. [LEVEL_EDITOR_TYPESELECT_FLOOR_BUTTON_OFF_PUSHED] =
  224. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButtonOffPushed.png", {-152, -252, 0, 0}, FALSE},
  225. [LEVEL_EDITOR_TYPESELECT_ITEM_BUTTON] =
  226. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton2.png", {-152, -214, 0, 0}, FALSE},
  227. [LEVEL_EDITOR_TYPESELECT_ITEM_BUTTON_PUSHED] =
  228. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton2Pushed.png", {-152, -214, 0, 0}, FALSE},
  229. [LEVEL_EDITOR_TYPESELECT_ITEM_BUTTON_OFF] =
  230. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton2Off.png", {-152, -214, 0, 0}, FALSE},
  231. [LEVEL_EDITOR_TYPESELECT_ITEM_BUTTON_OFF_PUSHED] =
  232. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton2OffPushed.png", {-152, -214, 0, 0}, FALSE},
  233. [LEVEL_EDITOR_TYPESELECT_WAYPOINT_BUTTON] =
  234. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton2.png", {-152, -176, 0, 0}, FALSE},
  235. [LEVEL_EDITOR_TYPESELECT_WAYPOINT_BUTTON_PUSHED] =
  236. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton2Pushed.png", {-152, -176, 0, 0}, FALSE},
  237. [LEVEL_EDITOR_TYPESELECT_WAYPOINT_BUTTON_OFF] =
  238. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton2Off.png", {-152, -176, 0, 0}, FALSE},
  239. [LEVEL_EDITOR_TYPESELECT_WAYPOINT_BUTTON_OFF_PUSHED] =
  240. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton2OffPushed.png", {-152, -176, 0, 0}, FALSE},
  241. [LEVEL_EDITOR_TYPESELECT_MAP_LABEL_BUTTON] =
  242. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton3.png", {-90, -176, 0, 0}, FALSE},
  243. [LEVEL_EDITOR_TYPESELECT_MAP_LABEL_BUTTON_PUSHED] =
  244. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton3Pushed.png", {-90, -176, 0, 0}, FALSE},
  245. [LEVEL_EDITOR_TYPESELECT_MAP_LABEL_BUTTON_OFF] =
  246. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton3Off.png", {-90, -176, 0, 0}, FALSE},
  247. [LEVEL_EDITOR_TYPESELECT_MAP_LABEL_BUTTON_OFF_PUSHED] =
  248. {EMPTY_IMAGE, "mouse_buttons/LevelEditorTypeSelectorButton3OffPushed.png", {-90, -176, 0, 0}, FALSE},
  249. [WEAPON_RECT_BUTTON] =
  250. {EMPTY_IMAGE, "THIS_DOESNT_NEED_BLITTING", {WEAPON_RECT_X, WEAPON_RECT_Y, WEAPON_RECT_WIDTH, WEAPON_RECT_HEIGHT}, FALSE},
  251. [DRIVE_RECT_BUTTON] =
  252. {EMPTY_IMAGE, "THIS_DOESNT_NEED_BLITTING", {DRIVE_RECT_X, DRIVE_RECT_Y, DRIVE_RECT_WIDTH, DRIVE_RECT_HEIGHT}, FALSE},
  253. [SHIELD_RECT_BUTTON] =
  254. {EMPTY_IMAGE, "THIS_DOESNT_NEED_BLITTING", {SHIELD_RECT_X, SHIELD_RECT_Y, SHIELD_RECT_WIDTH, SHIELD_RECT_HEIGHT}, FALSE},
  255. [HELMET_RECT_BUTTON] =
  256. {EMPTY_IMAGE, "THIS_DOESNT_NEED_BLITTING", {HELMET_RECT_X, HELMET_RECT_Y, HELMET_RECT_WIDTH, HELMET_RECT_HEIGHT}, FALSE},
  257. [ARMOUR_RECT_BUTTON] =
  258. {EMPTY_IMAGE, "THIS_DOESNT_NEED_BLITTING", {ARMOUR_RECT_X, ARMOUR_RECT_Y, ARMOUR_RECT_WIDTH, ARMOUR_RECT_HEIGHT}, FALSE},
  259. [SCROLL_DIALOG_MENU_UP_BUTTON] =
  260. {EMPTY_IMAGE, "mouse_buttons/ScrollDialogMenuUp.png", {235, (480 - 20 - 130 - 20 - 2), 160, 20}, TRUE},
  261. [SCROLL_DIALOG_MENU_DOWN_BUTTON] =
  262. {EMPTY_IMAGE, "mouse_buttons/ScrollDialogMenuDown.png", {235, (480 - 22), 160, 20}, TRUE},
  263. [MORE_STR_BUTTON] =
  264. {EMPTY_IMAGE, "mouse_buttons/AttributePlusButton.png", {0 + STR_X + 53, STR_Y - 5, 38, 22}, FALSE},
  265. [MORE_MAG_BUTTON] =
  266. {EMPTY_IMAGE, "mouse_buttons/AttributePlusButton.png", {0 + STR_X + 53, MAG_Y - 5, 38, 22}, FALSE},
  267. [MORE_DEX_BUTTON] =
  268. {EMPTY_IMAGE, "mouse_buttons/AttributePlusButton.png", {0 + STR_X + 53, DEX_Y - 5, 38, 22}, FALSE},
  269. [MORE_VIT_BUTTON] =
  270. {EMPTY_IMAGE, "mouse_buttons/AttributePlusButton.png", {0 + STR_X + 53, VIT_Y - 5, 38, 22}, FALSE},
  271. // These two buttons are for the scrolling text during the
  272. // title display, the credits menu and the level editor
  273. // keyboard explanation...
  274. //
  275. [SCROLL_TEXT_UP_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/arrow_up_for_scroll_text.png", {-65, 10, 73, 98}, FALSE},
  276. [SCROLL_TEXT_DOWN_BUTTON] =
  277. {EMPTY_IMAGE, "mouse_buttons/arrow_down_for_scroll_text.png", {-65, -10 - 98, 73, 98}, FALSE},
  278. [DESCRIPTION_WINDOW_UP_BUTTON] = {EMPTY_IMAGE, "THIS_DOESNT_NEED_BLITTING", {607, 99, 26, 26}, TRUE},
  279. [DESCRIPTION_WINDOW_DOWN_BUTTON] = {EMPTY_IMAGE, "THIS_DOESNT_NEED_BLITTING", {607, 347, 26, 26}, TRUE},
  280. [DROID_SHOW_EXIT_BUTTON] = {EMPTY_IMAGE, "THIS_DOESNT_NEED_BLITTING", {202, 311, 47, 47}, TRUE},
  281. // These are the scrollbuttons for the chat protocal inside the
  282. // chat window, like when talking to a character/bot.
  283. //
  284. [CHAT_LOG_SCROLL_UP_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/ScrollDialogMenuUp.png", {342, 3, 160, 20}, TRUE},
  285. [CHAT_LOG_SCROLL_DOWN_BUTTON] =
  286. {EMPTY_IMAGE, "mouse_buttons/ScrollDialogMenuDown.png", {342, 272, 160, 20}, TRUE},
  287. [CHAT_LOG_SCROLL_OFF_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/ScrollDialogMenuOff.png", {342, 3, 160, 20}, TRUE},
  288. [CHAT_LOG_SCROLL_OFF2_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/ScrollDialogMenuOff.png", {342, 272, 160, 20}, TRUE},
  289. [QUEST_BROWSER_ITEM_SHORT_BUTTON] =
  290. {EMPTY_IMAGE, "mouse_buttons/quest_browser_item_short.png", {108, 86, 300, 26}, FALSE},
  291. [QUEST_BROWSER_ITEM_LONG_BUTTON] =
  292. {EMPTY_IMAGE, "mouse_buttons/quest_browser_item_long.png", {108, 86, 300, 26}, FALSE},
  293. [TAKEOVER_HELP_BUTTON] = {EMPTY_IMAGE, "mouse_buttons/takeover_help_button.png", {78, 23, 153, 38}, FALSE},
  294. // Buttons of the item upgrade UI.
  295. [ITEM_UPGRADE_APPLY_BUTTON] = { EMPTY_IMAGE, "item_upgrade/button_apply.png",
  296. { ITEM_UPGRADE_RECT_X + 250, ITEM_UPGRADE_RECT_Y + 389, 48, 48 }, FALSE},
  297. [ITEM_UPGRADE_APPLY_BUTTON_DISABLED] = { EMPTY_IMAGE, "item_upgrade/button_apply_disabled.png",
  298. { ITEM_UPGRADE_RECT_X + 250, ITEM_UPGRADE_RECT_Y + 389, 48, 48 }, FALSE},
  299. [ITEM_UPGRADE_CLOSE_BUTTON] = { EMPTY_IMAGE, "item_upgrade/button_close.png",
  300. { ITEM_UPGRADE_RECT_X + 215, ITEM_UPGRADE_RECT_Y + 406, 32, 32 }, FALSE},
  301. // Buttons of the add-on crafting UI.
  302. [ADDON_CRAFTING_APPLY_BUTTON] = { EMPTY_IMAGE, "item_upgrade/button_apply.png",
  303. { ADDON_CRAFTING_RECT_X + 250, ADDON_CRAFTING_RECT_Y + 389, 48, 48 }, FALSE},
  304. [ADDON_CRAFTING_APPLY_BUTTON_DISABLED] = { EMPTY_IMAGE, "item_upgrade/button_apply_disabled.png",
  305. { ADDON_CRAFTING_RECT_X + 250, ADDON_CRAFTING_RECT_Y + 389, 48, 48 }, FALSE},
  306. [ADDON_CRAFTING_CLOSE_BUTTON] = { EMPTY_IMAGE, "item_upgrade/button_close.png",
  307. { ADDON_CRAFTING_RECT_X + 215, ADDON_CRAFTING_RECT_Y + 406, 32, 32 }, FALSE},
  308. [ADDON_CRAFTING_SCROLL_UP_BUTTON] = { EMPTY_IMAGE, "mouse_buttons/crafting_scroll_up.png",
  309. { ADDON_CRAFTING_RECT_X + 264, ADDON_CRAFTING_RECT_Y + 70, 32, 32 }, FALSE},
  310. [ADDON_CRAFTING_SCROLL_DOWN_BUTTON] = { EMPTY_IMAGE, "mouse_buttons/crafting_scroll_down.png",
  311. { ADDON_CRAFTING_RECT_X + 264, ADDON_CRAFTING_RECT_Y + 198, 32, 32 }, FALSE},
  312. [ADDON_CRAFTING_SCROLL_DESC_UP_BUTTON] = { EMPTY_IMAGE, "mouse_buttons/crafting_scroll_up.png",
  313. { ADDON_CRAFTING_RECT_X + 260, ADDON_CRAFTING_RECT_Y + 290, 32, 32 }, FALSE},
  314. [ADDON_CRAFTING_SCROLL_DESC_DOWN_BUTTON] = { EMPTY_IMAGE, "mouse_buttons/crafting_scroll_down.png",
  315. { ADDON_CRAFTING_RECT_X + 260, ADDON_CRAFTING_RECT_Y + 350, 32, 32 }, FALSE},
  316. }; // mouse_press_button AllMousePressButtons[ MAX_MOUSE_PRESS_BUTTONS ]
  317. //--------------------
  318. // We make these global variables here, as we might want to use
  319. // this function inside a signal handler and maybe also it's better
  320. // not to mess too much around with the stack while trying to read
  321. // out the stack...
  322. //
  323. #define MAX_CALLS_IN_BACKTRACE 200
  324. void *backtrace_array[MAX_CALLS_IN_BACKTRACE];
  325. size_t backtrace_size;
  326. char **backtrace_strings;
  327. size_t backtrace_counter;
  328. /**
  329. * Obtain a backtrace and print it to stdout.
  330. * If signum != 0, call Terminate()
  331. */
  332. void print_trace(int signum)
  333. {
  334. #if (!defined __WIN32__) && (!defined __APPLE_CC__) && (defined HAVE_BACKTRACE)
  335. // fprintf ( stderr , "print_trace: Now attempting backtrace from within the code!\n" );
  336. // fprintf ( stderr , "print_trace: Allowing a maximum of %d function calls on the stack!\n" , MAX_CALLS_IN_BACKTRACE );
  337. // We attempt to get a backtrace of all function calls so far, even
  338. // including the operating system (or rather libc) call to main() in
  339. // the beginning of execution.
  340. //
  341. backtrace_size = backtrace(backtrace_array, MAX_CALLS_IN_BACKTRACE);
  342. fprintf(stderr, "print_trace: Obtained %zd stack frames.\n", backtrace_size);
  343. // Now we attempt to translate the trace information we've got to the
  344. // symbol names that might still reside in the binary.
  345. //
  346. // NOTE: that in order for this to work, the -rdynamic switch must have
  347. // been passed as on option to the LINKER!
  348. // Also there might be a problem with non-ELF binaries, but let's
  349. // hope that it still works...
  350. //
  351. backtrace_strings = backtrace_symbols(backtrace_array, backtrace_size);
  352. fprintf(stderr, "print_trace: Obtaining symbols now done.\n");
  353. for (backtrace_counter = 0; backtrace_counter < backtrace_size; backtrace_counter++)
  354. fprintf(stderr, "%s\n", backtrace_strings[backtrace_counter]);
  355. // The strings generated in the backtrace_symbols function need to
  356. // get freed. Well, this isn't terribly important, but clean.
  357. //
  358. free(backtrace_strings);
  359. #endif
  360. switch (signum) {
  361. case 0:
  362. return;
  363. break;
  364. case SIGSEGV:
  365. fprintf(stderr, "\n%s(): received SIGSEGV!\n", __FUNCTION__);
  366. break;
  367. case SIGFPE:
  368. fprintf(stderr, "\n%s(): received SIGFPE!\n", __FUNCTION__);
  369. break;
  370. default:
  371. fprintf(stderr, "\n%s(): received UNKNOWN SIGNAL %d! ERROR! \n", __FUNCTION__, signum);
  372. }
  373. Terminate(EXIT_FAILURE, TRUE);
  374. }; // void print_trace ( int sig_num )
  375. /**
  376. * If we want the screen resolution to be a runtime option and not a
  377. * compile time option any more, we must not use it as a constant. That
  378. * means we must adapt the button positions to the current screen
  379. * resolution at runtime to, so we do it in this function, which will be
  380. * involved at program startup.
  381. */
  382. void adapt_button_positions_to_screen_resolution(void)
  383. {
  384. int i;
  385. for (i = 0; i < MAX_MOUSE_PRESS_BUTTONS; i++) {
  386. if (AllMousePressButtons[i].button_rect.x < 0)
  387. AllMousePressButtons[i].button_rect.x += GameConfig.screen_width;
  388. if (AllMousePressButtons[i].button_rect.y < 0)
  389. AllMousePressButtons[i].button_rect.y += GameConfig.screen_height;
  390. }
  391. AllMousePressButtons[OPEN_CLOSE_SKILL_EXPLANATION_BUTTON].button_rect.x += CHARACTERRECT_X;
  392. AllMousePressButtons[MORE_STR_BUTTON].button_rect.x += CHARACTERRECT_X;
  393. AllMousePressButtons[MORE_MAG_BUTTON].button_rect.x += CHARACTERRECT_X;
  394. AllMousePressButtons[MORE_DEX_BUTTON].button_rect.x += CHARACTERRECT_X;
  395. AllMousePressButtons[MORE_VIT_BUTTON].button_rect.x += CHARACTERRECT_X;
  396. Droid_Image_Window.x = 48 * GameConfig.screen_width / 640;
  397. Droid_Image_Window.y = 44 * GameConfig.screen_height / 480;
  398. Droid_Image_Window.w = 130 * GameConfig.screen_width / 640;
  399. Droid_Image_Window.h = 172 * GameConfig.screen_height / 480;
  400. Full_User_Rect.x = 0;
  401. Full_User_Rect.y = 0;
  402. Full_User_Rect.w = GameConfig.screen_width;
  403. Full_User_Rect.h = GameConfig.screen_height;
  404. Cons_Text_Rect.x = 175;
  405. Cons_Text_Rect.y = 180;
  406. Cons_Text_Rect.w = GameConfig.screen_width - 175;
  407. Cons_Text_Rect.h = 305;
  408. }; // void adapt_button_positions_to_screen_resolution( void )
  409. /**
  410. * This is a useful utility sub-function for the checks whether the
  411. * mouse cursor is on an enemy, a closed chest or a barrel, or any other object.
  412. * The function detects if the current mouse cursor is over the graphics
  413. * mentioned in that iso image, using the given position from the
  414. * parameter list.
  415. *
  416. * TRUE or FALSE is returned, depending on whether the cursor IS or
  417. * IS NOT on that particular iso_image, if positioned on that given spot.
  418. */
  419. int mouse_cursor_is_on_that_image(float pos_x, float pos_y, struct image *our_image)
  420. {
  421. // our_iso_image = & ( enemy_iso_images [ RotationModel ] [ RotationIndex ] [ (int) this_bot -> animation_phase ] ) ;
  422. SDL_Rect screen_rectangle;
  423. screen_rectangle.x = translate_map_point_to_screen_pixel_x(pos_x, pos_y) + our_image->offset_x;
  424. screen_rectangle.y = translate_map_point_to_screen_pixel_y(pos_x, pos_y) + our_image->offset_y;
  425. screen_rectangle.w = our_image->w;
  426. screen_rectangle.h = our_image->h;
  427. if (MouseCursorIsInRect(&(screen_rectangle),
  428. input_axis.x + User_Rect.w / 2 + User_Rect.x, input_axis.y + User_Rect.h / 2 + User_Rect.y)) {
  429. return (TRUE);
  430. }
  431. return (FALSE);
  432. }
  433. /**
  434. * This function checks if a given screen position lies within the
  435. * inventory screen toggle button or not.
  436. */
  437. int MouseCursorIsInRect(const SDL_Rect *our_rect, int x, int y)
  438. {
  439. // Now we can start to check if the mouse cursor really is on that
  440. // rectangle or not.
  441. //
  442. if (x > our_rect->x + our_rect->w)
  443. return (FALSE);
  444. if (x < our_rect->x)
  445. return (FALSE);
  446. if (y > our_rect->y + our_rect->h)
  447. return (FALSE);
  448. if (y < our_rect->y)
  449. return (FALSE);
  450. // So since the cursor is not outside of this rectangle, it must
  451. // we inside, and so we'll return this answer.
  452. //
  453. return (TRUE);
  454. }; // int MouseCursorIsInRect( SDL_rect* our_rect , int x , int y )
  455. /**
  456. * This function checks if a given screen position lies within the
  457. * inventory screen toggle button or not.
  458. */
  459. int MouseCursorIsOnButton(int ButtonIndex, int x, int y)
  460. {
  461. SDL_Rect temp_rect;
  462. // First a sanity check if the button index given does make
  463. // some sense.
  464. //
  465. if ((ButtonIndex >= MAX_MOUSE_PRESS_BUTTONS) || (ButtonIndex < 0)) {
  466. ErrorMessage(__FUNCTION__, "\
  467. A Button that should be checked for mouse contact was requested, but the\n\
  468. button index given exceeds the number of buttons defined in FreedroidRPG.", PLEASE_INFORM, IS_FATAL);
  469. }
  470. Copy_Rect(AllMousePressButtons[ButtonIndex].button_rect, temp_rect);
  471. // If this button needs scaling still, then we do it now...
  472. //
  473. if (AllMousePressButtons[ButtonIndex].scale_this_button) {
  474. temp_rect.x *= ((float)GameConfig.screen_width) / 640.0;
  475. temp_rect.w *= ((float)GameConfig.screen_width) / 640.0;
  476. temp_rect.y *= ((float)GameConfig.screen_height) / 480.0;
  477. temp_rect.h *= ((float)GameConfig.screen_height) / 480.0;
  478. }
  479. if (y < AllMousePressButtons[ButtonIndex].button_rect.y)
  480. return (FALSE);
  481. // So since the cursor is not outside of this rectangle, it must
  482. // we inside, and so we'll return this answer.
  483. //
  484. return (MouseCursorIsInRect(&(temp_rect), x, y));
  485. }; // int MouseCursorIsOnButton( int ButtonIndex , int x , int y )
  486. /**
  487. * Draw a button on the screen.
  488. */
  489. void ShowGenericButtonFromList(int ButtonIndex)
  490. {
  491. struct mouse_press_button *btn;
  492. // Safety check
  493. if ((ButtonIndex >= MAX_MOUSE_PRESS_BUTTONS) || (ButtonIndex < 0)) {
  494. ErrorMessage(__FUNCTION__, "Request to display button index %d could not be fulfilled: the\n\
  495. button index given exceeds the number of buttons defined in FreedroidRPG.", PLEASE_INFORM, IS_WARNING_ONLY, ButtonIndex);
  496. return;
  497. }
  498. btn = &AllMousePressButtons[ButtonIndex];
  499. // Some buttons have no graphics, in this case there is nothing to do.
  500. if (!strcmp(AllMousePressButtons[ButtonIndex].button_image_file_name, "THIS_DOESNT_NEED_BLITTING")) {
  501. return;
  502. }
  503. // Compute scaling factors for button
  504. float scale_x = 1.0, scale_y = 1.0;
  505. if (btn->scale_this_button) {
  506. scale_x = ((float)GameConfig.screen_width) / 640.0;
  507. scale_y = ((float)GameConfig.screen_height) / 480.0;
  508. }
  509. // Load button image if required
  510. struct image *img = &btn->button_image;
  511. if (!image_loaded(img)) {
  512. load_image(img, btn->button_image_file_name, FALSE);
  513. // Maybe we had '0' entries for the height or width of this button in the list.
  514. // This means that we will take the real width and the real height from the image
  515. // and overwrite the 0 entries with this.
  516. //
  517. if (!btn->button_rect.w) {
  518. btn->button_rect.w = img->w;
  519. }
  520. if (!btn->button_rect.h) {
  521. btn->button_rect.h = img->h;
  522. }
  523. }
  524. display_image_on_screen(img, AllMousePressButtons[ButtonIndex].button_rect.x * scale_x, AllMousePressButtons[ButtonIndex].button_rect.y * scale_y, set_image_transformation(scale_x, scale_y, 1.0, 1.0, 1.0, 1.0, 0));
  525. }
  526. /* -----------------------------------------------------------------
  527. * find a given filename in subdir relative to FD_DATADIR,
  528. *
  529. * if you pass NULL as subdir, it will be ignored
  530. *
  531. * fills in the (ALLOC'd) string and returns 0 if okay, 1 on error
  532. *
  533. * ----------------------------------------------------------------- */
  534. int find_file(const char *fname, const char *subdir, char *File_Path, int silent)
  535. {
  536. int i;
  537. FILE *fp; // this is the file we want to find?
  538. *File_Path = 0;
  539. if (!subdir)
  540. subdir = "";
  541. for (i = 0; i < 4; i++) {
  542. if (i == 0)
  543. sprintf((File_Path), "."); /* first try local subdirs */
  544. if (i == 1)
  545. sprintf((File_Path), ".."); /* first try local subdirs */
  546. if (i == 2)
  547. sprintf((File_Path), "../.."); /* first try local subdirs */
  548. if (i == 3)
  549. sprintf((File_Path), "%s", FD_DATADIR); /* then the DATADIR */
  550. strcat((File_Path), "/");
  551. strcat((File_Path), subdir);
  552. strcat((File_Path), "/");
  553. strcat((File_Path), fname);
  554. if ((fp = fopen((File_Path), "r")) != NULL) { /* found it? */
  555. fclose(fp);
  556. break;
  557. } else {
  558. if (i != 3)
  559. DebugPrintf(1, "\nfind_file could not succeed with LOCAL path: %s.", File_Path);
  560. else {
  561. if (!silent) {
  562. DebugPrintf(-4, "The file name was: %s.\n", fname);
  563. ErrorMessage(__FUNCTION__, "File not found ", NO_NEED_TO_INFORM, IS_WARNING_ONLY);
  564. }
  565. return 1;
  566. }
  567. }
  568. } // for i
  569. // DebugPrintf( 0 , "\nfind_file determined file path: %s." , File_Path );
  570. return 0;
  571. }; // char * find_file ( ... )
  572. /**
  573. * This function realizes the Pause-Mode: the game process is halted,
  574. * while the graphics and animations are not. This mode
  575. * can further be toggled from PAUSE to CHEESE, which is
  576. * a feature from the original program that should probably
  577. * allow for better screenshots.
  578. */
  579. void Pause(void)
  580. {
  581. int Pause = TRUE;
  582. int cheese = FALSE; /* cheese mode: do not display GAME PAUSED - nicer screenshots */
  583. SDL_Event event;
  584. SDLKey key;
  585. Activate_Conservative_Frame_Computation();
  586. AssembleCombatPicture(DO_SCREEN_UPDATE);
  587. input_get_keybind("pause", &key, NULL);
  588. while (Pause) {
  589. SDL_WaitEvent(&event);
  590. if (event.type == SDL_QUIT) {
  591. Terminate(EXIT_SUCCESS, TRUE);
  592. }
  593. AssembleCombatPicture(0);
  594. if (!cheese)
  595. CenteredPutStringFont(Screen, Menu_BFont, 200, _("GAME PAUSED"));
  596. CenteredPutStringFont(Screen, Menu_BFont, 230, _("press p to resume"));
  597. our_SDL_flip_wrapper();
  598. if (event.type == SDL_KEYDOWN) {
  599. if (event.key.keysym.sym == key) {
  600. Pause = FALSE;
  601. } else if (event.key.keysym.sym == SDLK_c) {
  602. cheese = !cheese;
  603. }
  604. }
  605. SDL_Delay(10);
  606. }
  607. return;
  608. }
  609. /**
  610. * This function prevents any action from taking place in the game world.
  611. *
  612. * Interaction with the user interface is unaffected.
  613. */
  614. void freeze_world()
  615. {
  616. // Because different UI elements may try to freeze the game world,
  617. // it's necessary to count how many times this function has been
  618. // called.
  619. world_is_frozen++;
  620. }
  621. /**
  622. * This function unfreezes the game world.
  623. *
  624. * NOTE: unfreeze_world() must be called for each call to freeze_world().
  625. */
  626. void unfreeze_world()
  627. {
  628. if (world_is_frozen > 0)
  629. world_is_frozen--;
  630. }
  631. /**
  632. * This function returns the current state of the game world.
  633. * @return TRUE if the game world is currently frozen.
  634. */
  635. int world_frozen()
  636. {
  637. return (world_is_frozen > 0);
  638. }
  639. /**
  640. * This function starts the time-taking process. Later the results
  641. * of this function will be used to calculate the current framerate
  642. */
  643. void StartTakingTimeForFPSCalculation(void)
  644. {
  645. /* This ensures, that 0 is never an encountered framenr,
  646. * therefore count to 100 here
  647. * Take the time now for calculating the frame rate
  648. * (DO NOT MOVE THIS COMMAND PLEASE!) */
  649. framenr++;
  650. One_Frame_SDL_Ticks = SDL_GetTicks();
  651. if (framenr % 10 == 1)
  652. Ten_Frame_SDL_Ticks = SDL_GetTicks();
  653. if (framenr % 100 == 1) {
  654. Onehundred_Frame_SDL_Ticks = SDL_GetTicks();
  655. }
  656. }; // void StartTakingTimeForFPSCalculation(void)
  657. /**
  658. * This function computes the framerate that has been experienced
  659. * in this frame. It will be used to correctly calibrate all
  660. * movements of game objects.
  661. *
  662. * NOTE: To query the actual framerate a DIFFERENT function must
  663. * be used, namely Frame_Time().
  664. */
  665. void ComputeFPSForThisFrame(void)
  666. {
  667. Now_SDL_Ticks = SDL_GetTicks();
  668. oneframedelay = Now_SDL_Ticks - One_Frame_SDL_Ticks;
  669. tenframedelay = Now_SDL_Ticks - Ten_Frame_SDL_Ticks;
  670. onehundredframedelay = Now_SDL_Ticks - Onehundred_Frame_SDL_Ticks;
  671. if (!oneframedelay)
  672. FPSover1 = 1000 * 1 / 0.5;
  673. else
  674. FPSover1 = 1000 * 1 / (float)oneframedelay;
  675. if (!tenframedelay)
  676. FPSover10 = 1000 * 10 / 0.5;
  677. else
  678. FPSover10 = 1000 * 10 / (float)tenframedelay;
  679. if (!onehundredframedelay)
  680. FPSover100 = 1000 * 100 / 0.5;
  681. else
  682. FPSover100 = 1000 * 100 / (float)onehundredframedelay;
  683. }; // void ComputeFPSForThisFrame(void)
  684. /**
  685. *
  686. * This function is the key to independence of the framerate for various game elements.
  687. * It returns the average time needed to draw one frame.
  688. * Other functions use this to calculate new positions of moving objects, etc..
  689. *
  690. * Also there is of course a serious problem when some interruption occurs, like e.g.
  691. * the options menu is called or the debug menu is called or the console or the elevator
  692. * is entered or a takeover game takes place. This might cause HUGE framerates, that could
  693. * box the influencer out of the ship if used to calculate the new position.
  694. *
  695. * To counter unwanted effects after such events we have the SkipAFewFramerates counter,
  696. * which instructs Rate_To_Be_Returned to return only the overall default framerate since
  697. * no better substitute exists at this moment. But on the other hand, this seems to
  698. * work REALLY well this way.
  699. *
  700. * This counter is most conveniently set via the function Activate_Conservative_Frame_Computation,
  701. * which can be conveniently called from eveywhere.
  702. *
  703. */
  704. float Frame_Time(void)
  705. {
  706. float Rate_To_Be_Returned;
  707. if (SkipAFewFrames) {
  708. Rate_To_Be_Returned = Overall_Average;
  709. return Rate_To_Be_Returned;
  710. }
  711. Rate_To_Be_Returned = (1.0 / FPSover1);
  712. return Rate_To_Be_Returned;
  713. }
  714. int Get_Average_FPS(void)
  715. {
  716. return ((int)(1.0 / Overall_Average));
  717. }; // int Get_Average_FPS( void )
  718. /**
  719. *
  720. * With framerate computation, there is a problem when some interruption occurs, like e.g.
  721. * the options menu is called or the debug menu is called or the console or the elevator
  722. * is entered or a takeover game takes place. This might cause HUGE framerates, that could
  723. * box the influencer out of the ship if used to calculate the new position.
  724. *
  725. * To counter unwanted effects after such events we have the SkipAFewFramerates counter,
  726. * which instructs Rate_To_Be_Returned to return only the overall default framerate since
  727. * no better substitute exists at this moment.
  728. *
  729. * This counter is most conveniently set via the function Activate_Conservative_Frame_Computation,
  730. * which can be conveniently called from everywhere.
  731. *
  732. */
  733. void Activate_Conservative_Frame_Computation(void)
  734. {
  735. // SkipAFewFrames=212;
  736. // SkipAFewFrames=22;
  737. SkipAFewFrames = 3;
  738. DebugPrintf(1, "\nConservative_Frame_Computation activated!");
  739. }; // void Activate_Conservative_Frame_Computation(void)
  740. /*
  741. * Should be called in every frame when counting FPS
  742. */
  743. void update_frames_displayed(void)
  744. {
  745. // The next couter counts the frames displayed by FreedroidRPG during this
  746. // whole run!! DO NOT RESET THIS COUNTER WHEN THE GAME RESTARTS!!
  747. Overall_Frames_Displayed++;
  748. Overall_Average = (Overall_Average * (Overall_Frames_Displayed - 1)
  749. + Frame_Time()) / Overall_Frames_Displayed;
  750. if (SkipAFewFrames)
  751. SkipAFewFrames--;
  752. }
  753. /**
  754. * This function is used to generate an integer in range of all
  755. * numbers from 0 to UpperBound.
  756. */
  757. int MyRandom(int UpperBound)
  758. {
  759. if (!UpperBound)
  760. return 0;
  761. float tmp;
  762. int PureRandom;
  763. int dice_val; /* the result in [0, UpperBound] */
  764. PureRandom = rand();
  765. tmp = 1.0 * PureRandom / RAND_MAX; /* random number in [0;1] */
  766. /*
  767. * we always round OFF for the resulting int, therefore
  768. * we first add 0.99999 to make sure that UpperBound has
  769. * roughly the same probablity as the other numbers
  770. */
  771. dice_val = (int)(tmp * (1.0 * UpperBound + 0.99999));
  772. return (dice_val);
  773. }; // int MyRandom ( int UpperBound )
  774. /**
  775. * This function teleports the influencer to a new position on the
  776. * ship. THIS CAN BE A POSITION ON A DIFFERENT LEVEL.
  777. */
  778. void Teleport(int LNum, float X, float Y, int with_sound_and_fading, int with_animation_reset)
  779. {
  780. // Check if we are in editor and not in game test mode then we store the level number
  781. //
  782. if(game_root_mode == ROOT_IS_LVLEDIT && game_status != INSIDE_GAME)
  783. GameConfig.last_edited_level = LNum;
  784. // Maybe the 'teleport' really comes from a teleportation device or
  785. // teleport spell or maybe even from accessing some sewer access way.
  786. // In that case we'll fade out the screen a bit using the gamma ramp
  787. // and then later back in again. (Note that this is a blocking function
  788. // call, i.e. it will take a second or so each.)
  789. //
  790. if (with_sound_and_fading) {
  791. fade_out_screen();
  792. }
  793. if (LNum != Me.pos.z) {
  794. // Notify level change events on this level
  795. if (game_status == INSIDE_GAME)
  796. event_level_changed(Me.pos.z, LNum);
  797. // In case a real level change has happened,
  798. // we need to do a lot of work. Therefore we start by activating
  799. // the conservative frame time computation to avoid a 'jump'.
  800. //
  801. Activate_Conservative_Frame_Computation();
  802. Me.pos.x = X;
  803. Me.pos.y = Y;
  804. Me.pos.z = LNum;
  805. item_held_in_hand = NULL;
  806. // We add some sanity check against teleporting to non-allowed
  807. // locations (like outside of map that is)
  808. //
  809. if (!level_exists(LNum) || !pos_inside_level(Me.pos.x, Me.pos.y, curShip.AllLevels[LNum])) {
  810. fprintf(stderr, "\n\ntarget location was: lev=%d x=%f y=%f.\n", LNum, X, Y);
  811. fprintf(stderr, "source location was: lev=%d x=%f y=%f.", Me.pos.z, Me.pos.x, Me.pos.y);
  812. ErrorMessage(__FUNCTION__, "\
  813. A Teleport was requested, but the location to teleport to lies beyond\n\
  814. the bounds of this 'ship' which means the current collection of levels.\n\
  815. This indicates an error in the map system of FreedroidRPG.", PLEASE_INFORM, IS_FATAL);
  816. }
  817. // Refresh some speed-up data structures
  818. get_visible_levels();
  819. } else {
  820. // If no real level change has occurred, everything
  821. // is simple and we just need to set the new coordinates, haha
  822. //
  823. Me.pos.x = X;
  824. Me.pos.y = Y;
  825. // Teleport could have been called by the leveleditor, due to
  826. // some changes in the current level (light values, for example),
  827. // so we refresh the speed-up data structures
  828. get_visible_levels();
  829. }
  830. // After the teleport, the mouse move target might be
  831. // completely out of date. Therefore we simply delete it. In cases
  832. // where the jump came from crossing a jump threshold (levels glued
  833. // together) we can still restore the move target in that (the calling!)
  834. // function.
  835. //
  836. Me.mouse_move_target.x = Me.pos.x;
  837. Me.mouse_move_target.y = Me.pos.y;
  838. Me.mouse_move_target.z = Me.pos.z;
  839. Me.mouse_move_target_combo_action_type = NO_COMBO_ACTION_SET;
  840. // Animate Tux as standing still
  841. if (with_animation_reset) {
  842. Me.walk_cycle_phase = 0.0;
  843. Me.phase = tux_anim.standing_keyframe;
  844. }
  845. if (with_sound_and_fading) {
  846. teleport_arrival_sound();
  847. }
  848. // Perhaps the player is visiting this level for the first time. Then, the
  849. // tux should make it's initial statement about the location, if there is one.
  850. //
  851. if (!Me.HaveBeenToLevel[Me.pos.z]) {
  852. Me.HaveBeenToLevel[Me.pos.z] = TRUE;
  853. }
  854. SwitchBackgroundMusicTo(CURLEVEL()->Background_Song_Name);
  855. // Since we've mightily changed position now, we should clear the
  856. // position history, so that no one gets confused...
  857. //
  858. InitInfluPositionHistory();
  859. if (with_sound_and_fading) {
  860. append_new_game_message(_("Arrived at %s."), D_(curShip.AllLevels[Me.pos.z]->Levelname));
  861. fade_in_screen();
  862. }
  863. }
  864. /**
  865. * Teleport the influencer to the center of a level on the ship
  866. * \param level_num The number of the level where we want to be teleported
  867. */
  868. void teleport_to_level_center(int level_num)
  869. {
  870. // Calculate the center of the level
  871. float x = curShip.AllLevels[level_num]->xlen / 2;
  872. float y = curShip.AllLevels[level_num]->ylen / 2;
  873. // Teleporting to the center of the level
  874. Teleport(level_num, x, y, FALSE, TRUE);
  875. }
  876. /**
  877. * Check if a level exists.
  878. * \param level_num The number of the level.
  879. * \return TRUE if the level exists.
  880. */
  881. int level_exists(int level_num)
  882. {
  883. if (level_num < 0 || level_num >= curShip.num_levels) {
  884. return FALSE;
  885. }
  886. if (curShip.AllLevels[level_num] == NULL) {
  887. return FALSE;
  888. }
  889. return TRUE;
  890. }
  891. /*----------------------------------------------------------------------
  892. * LoadGameConfig(): load saved options from config-file
  893. *
  894. * this should be the first of all load/save functions called
  895. * as here we read the $HOME-dir and create the config-subdir if necessary
  896. *
  897. *----------------------------------------------------------------------*/
  898. int LoadGameConfig(void)
  899. {
  900. char fname[5000];
  901. FILE *configfile;
  902. if (!our_config_dir) {
  903. DebugPrintf(1, "No useable config-dir. No config-loading possible\n");
  904. return (OK);
  905. }
  906. sprintf(fname, "%s/fdrpg.cfg", our_config_dir);
  907. if ((configfile = fopen(fname, "rb")) == NULL) {
  908. fprintf(stderr, "Unable to open configuration file %s\n", fname);
  909. return (ERR);
  910. }
  911. char *stuff = (char *)malloc(FS_filelength(configfile) + 1);
  912. if (fread(stuff, FS_filelength(configfile), 1, configfile) != 1) {
  913. ErrorMessage(__FUNCTION__, "Failed to read config file: %s.\n", NO_NEED_TO_INFORM, IS_WARNING_ONLY, fname);
  914. fclose(configfile);
  915. free(stuff);
  916. return ERR;
  917. }
  918. stuff[FS_filelength(configfile)] = 0;
  919. fclose(configfile);
  920. if (setjmp(saveload_jmpbuf)) {
  921. ErrorMessage(__FUNCTION__, "Failed to read config file: %s.\n", NO_NEED_TO_INFORM, IS_WARNING_ONLY, fname);
  922. configfile = NULL;
  923. free(stuff);
  924. ResetGameConfigToDefaultValues();
  925. return ERR;
  926. }
  927. load_freedroid_configuration(stuff);
  928. configfile = NULL;
  929. free(stuff);
  930. if (!GameConfig.freedroid_version_string || strcmp(GameConfig.freedroid_version_string, VERSION)) {
  931. ErrorMessage(__FUNCTION__, "\
  932. Settings file found in your ~/.freedroid_rpg dir does not\n\
  933. seem to be from the same version as this installation of FreedroidRPG.\n\
  934. This is perfectly normal if you have just upgraded your version of\n\
  935. FreedroidRPG. However, the loading of your settings will be canceled now,\n\
  936. because the format of the settings file is no longer supported.\n\
  937. No need to panic. The default settings will be used instead and a new\n\
  938. settings file will be generated.\n", NO_NEED_TO_INFORM, IS_WARNING_ONLY);
  939. ResetGameConfigToDefaultValues();
  940. return (ERR);
  941. };
  942. // Now we will turn off the skills and inventory screen and that, cause
  943. // this should be off when the game starts...
  944. //
  945. GameConfig.CharacterScreen_Visible = FALSE;
  946. GameConfig.Inventory_Visible = FALSE;
  947. GameConfig.SkillScreen_Visible = FALSE;
  948. GameConfig.skill_explanation_screen_visible = FALSE;
  949. GameConfig.Automap_Visible = TRUE;
  950. return (OK);
  951. }
  952. /*----------------------------------------------------------------------
  953. * SaveGameConfig: do just that
  954. *
  955. *----------------------------------------------------------------------*/
  956. int SaveGameConfig(void)
  957. {
  958. char fname[5000];
  959. int current_width;
  960. int current_height;
  961. FILE *config_file;
  962. // Maybe the Terminate function was invoked BEFORE the startup process
  963. // was complete at all (like e.g. some illegal command line parameter).
  964. // Then the config dir is not initialized. We catch this case and return
  965. // control to the operating system immediately if that happens...
  966. //
  967. if (our_config_dir == NULL) {
  968. printf("It seems that the game couldn't start up at all... therefore we need not save any configuration information.\n\n");
  969. SDL_Quit();
  970. #if __WIN32__
  971. fflush(stdout);
  972. fflush(stderr);
  973. char *cmd = MyMalloc(strlen(our_config_dir) + 20);
  974. sprintf(cmd, "notepad %s/stderr.txt", our_config_dir);
  975. system(cmd);
  976. sprintf(cmd, "notepad %s/stdout.txt", our_config_dir);
  977. system(cmd);
  978. free(cmd);
  979. #endif
  980. exit(ERR);
  981. }
  982. // Now we know, that the config dir has been initialized already.
  983. // That indicates, that the game did start up already.
  984. // Therefore we can do the normal save config stuff...
  985. //
  986. if (our_config_dir[0] == '\0')
  987. return (ERR);
  988. sprintf(fname, "%s/fdrpg.cfg", our_config_dir);
  989. if ((config_file = fopen(fname, "wb")) == NULL) {
  990. fprintf(stderr, "Unable to open configuration file %s for writing\n", fname);
  991. return (ERR);
  992. }
  993. // We put the current version number of FreedroidRPG into the
  994. // version number string. This will be useful so that later
  995. // versions of FreedroidRPG can identify old config files and decide
  996. // not to use them in some cases.
  997. //
  998. if (GameConfig.freedroid_version_string) {
  999. free(GameConfig.freedroid_version_string);
  1000. }
  1001. GameConfig.freedroid_version_string = strdup(VERSION);
  1002. // We preserve the current resolution, modify it a bit, such that
  1003. // the preselected resolution will come to effect next time, save
  1004. // it and then we restore the current settings again.
  1005. //
  1006. current_width = GameConfig.screen_width;
  1007. current_height = GameConfig.screen_height;
  1008. GameConfig.screen_width = GameConfig.next_time_width_of_screen;
  1009. GameConfig.screen_height = GameConfig.next_time_height_of_screen;
  1010. // Now write the actual data
  1011. savestruct_autostr = alloc_autostr(4096);
  1012. save_freedroid_configuration(savestruct_autostr);
  1013. if (fwrite(savestruct_autostr->value, savestruct_autostr->length, 1, config_file) != 1) {
  1014. ErrorMessage(__FUNCTION__, "Failed to write configuration file: %s", NO_NEED_TO_INFORM, IS_WARNING_ONLY, fname);
  1015. free_autostr(savestruct_autostr);
  1016. return ERR;
  1017. }
  1018. free_autostr(savestruct_autostr);
  1019. GameConfig.screen_width = current_width;
  1020. GameConfig.screen_height = current_height;
  1021. fclose(config_file);
  1022. return (OK);
  1023. }; // int SaveGameConfig ( void )
  1024. /**
  1025. * This function is used for terminating freedroid. It will close
  1026. * the SDL submodules and exit.
  1027. */
  1028. void Terminate(int exit_code, int save_config)
  1029. {
  1030. printf("\n---------------------------------------------------------------------------------");
  1031. printf("\nTermination of freedroidRPG initiated... ");
  1032. // We save the config file in any case.
  1033. if (save_config)
  1034. SaveGameConfig();
  1035. printf("Thank you for playing freedroidRPG.\n\n");
  1036. SDL_Quit();
  1037. // Finally, especially on win32 systems, we should open an editor with
  1038. // the last debug output, since people in general won't know how and where
  1039. // to find the material for proper reporting of bugs.
  1040. #if __WIN32__
  1041. if (exit_code == EXIT_FAILURE) {
  1042. fflush(stdout);
  1043. fflush(stderr);
  1044. char *cmd = MyMalloc(strlen(our_config_dir) + 20);
  1045. sprintf(cmd, "notepad %s/stderr.txt", our_config_dir);
  1046. system(cmd);
  1047. sprintf(cmd, "notepad %s/stdout.txt", our_config_dir);
  1048. system(cmd);
  1049. free(cmd);
  1050. }
  1051. #endif
  1052. // Now we drop control back to the operating system. The FreedroidRPG
  1053. // program has finished.
  1054. exit(exit_code);
  1055. }
  1056. /**
  1057. * Return a pointer towards the obstacle designated by the given (unique) label.
  1058. * \param level_number If not NULL, this is set to the levelnumber where the obstacle was found.
  1059. */
  1060. obstacle *give_pointer_to_obstacle_with_label(const char *obstacle_label, int *level_number)
  1061. {
  1062. int i, j;
  1063. // On each level, browse the obstacle extensions until we find the label we are looking for
  1064. for (i = 0; i < curShip.num_levels; i++) {
  1065. level *l = curShip.AllLevels[i];
  1066. if (l == NULL)
  1067. continue;
  1068. for (j = 0; j < l->obstacle_extensions.size; j++) {
  1069. struct obstacle_extension *ext = &ACCESS_OBSTACLE_EXTENSION(l->obstacle_extensions, j);
  1070. if (ext->type == OBSTACLE_EXTENSION_LABEL) {
  1071. if (!strcmp(ext->data, obstacle_label)) {
  1072. if (level_number) {
  1073. *level_number = l->levelnum;
  1074. }
  1075. return ext->obs;
  1076. }
  1077. }
  1078. }
  1079. }
  1080. ErrorMessage(__FUNCTION__, "Obstacle label \"%s\" was not found on the map.", PLEASE_INFORM, IS_FATAL, obstacle_label);
  1081. return NULL;
  1082. }
  1083. /*----------------------------------------------------------------------
  1084. * try getting round endian-differences with minimal intervention
  1085. * to the code..
  1086. *
  1087. * read o…

Large files files are truncated, but you can click here to view the full file