Oblivion_UFF

physics.inc

Oct 13th, 2018
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 42.58 KB | None | 0 0
  1. /* <SA-MP Objects Physics - Handle collisions and more.>
  2. Copyright (C) <2013> <Peppe>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13.  
  14. #include <modelsizes>
  15. #pragma compress 1
  16. #include <foreach>
  17. #pragma tabsize 0
  18.  
  19. #if !defined PHY_TIMER_INTERVAL
  20. #define PHY_TIMER_INTERVAL (20)
  21. #endif
  22. #if !defined PHY_MAX_WALLS
  23. #define PHY_MAX_WALLS (512)
  24. #endif
  25. #if !defined PHY_MAX_CYLINDERS
  26. #define PHY_MAX_CYLINDERS (512)
  27. #endif
  28.  
  29. #define PHY_MODE_3D (0)
  30. #define PHY_MODE_2D (1)
  31.  
  32. #if !defined FLOAT_INFINITY
  33. #define FLOAT_INFINITY (Float:0x7F800000)
  34. #endif
  35. #if !defined FLOAT_NEG_INFINITY
  36. #define FLOAT_NEG_INFINITY (Float:0xFF800000)
  37. #endif
  38. #if !defined FLOAT_NAN
  39. #define FLOAT_NAN (Float:0xFFFFFFFF)
  40. #endif
  41.  
  42. /* Callbacks */
  43. forward PHY_OnObjectUpdate(objectid);
  44. forward PHY_OnObjectCollideWithObject(object1, object2);
  45. forward PHY_OnObjectCollideWithWall(objectid, wallid);
  46. forward PHY_OnObjectCollideWithCylinder(objectid, cylinderid);
  47. forward PHY_OnObjectCollideWithPlayer(objectid, playerid);
  48.  
  49.  
  50. enum (<<= 1)
  51. {
  52. PHY_OBJECT_USED = 0b01,
  53. PHY_OBJECT_MODE,
  54. PHY_OBJECT_ROLL,
  55. PHY_OBJECT_GHOST_OBJECTS,
  56. PHY_OBJECT_GHOST_WALLS,
  57. PHY_OBJECT_GHOST_CYLINDERS,
  58. PHY_OBJECT_PLAYER_COLLISIONS
  59. }
  60.  
  61. enum E_PHY_OBJECT
  62. {
  63. PHY_Properties,
  64. PHY_World,
  65. Float:PHY_Size,
  66. Float:PHY_Mass,
  67. Float:PHY_VX,
  68. Float:PHY_VY,
  69. Float:PHY_VZ,
  70. Float:PHY_AX,
  71. Float:PHY_AY,
  72. Float:PHY_AZ,
  73. Float:PHY_Friction,
  74. Float:PHY_AirResistance,
  75. Float:PHY_Gravity,
  76. Float:PHY_LowZBound,
  77. Float:PHY_HighZBound,
  78. Float:PHY_BoundConst,
  79. Float:PHY_PlayerConst,
  80. Float:PHY_PlayerDist,
  81. Float:PHY_PlayerLowZ,
  82. Float:PHY_PlayerHighZ
  83. }
  84.  
  85. new
  86. PHY_Object[MAX_OBJECTS][E_PHY_OBJECT],
  87. Iterator:ITER_Object<MAX_OBJECTS>;
  88.  
  89.  
  90. enum E_PHY_WALL
  91. {
  92. PHY_Created,
  93. PHY_World,
  94. Float:PHY_X1,
  95. Float:PHY_Y1,
  96. Float:PHY_X2,
  97. Float:PHY_Y2,
  98. Float:PHY_Z1,
  99. Float:PHY_Z2,
  100. Float:PHY_BounceConst,
  101. Float:PHY_ANG
  102. }
  103.  
  104. new
  105. PHY_Wall[PHY_MAX_WALLS][E_PHY_WALL],
  106. Iterator:ITER_Wall<PHY_MAX_WALLS>;
  107.  
  108.  
  109. enum E_PHY_CYLINDER
  110. {
  111. PHY_Created,
  112. PHY_World,
  113. Float:PHY_X,
  114. Float:PHY_Y,
  115. Float:PHY_Z1,
  116. Float:PHY_Z2,
  117. Float:PHY_Size,
  118. Float:PHY_BounceConst
  119. }
  120.  
  121. new
  122. PHY_Cylinder[PHY_MAX_CYLINDERS][E_PHY_CYLINDER],
  123. Iterator:ITER_Cylinder<PHY_MAX_CYLINDERS>;
  124.  
  125.  
  126. enum E_PHY_PLAYER
  127. {
  128. PHY_World
  129. }
  130.  
  131. new
  132. PHY_Player[MAX_PLAYERS][E_PHY_PLAYER];
  133.  
  134.  
  135. /* Macros are self-explanatory */
  136. #define PHY_IsObjectUsingPhysics(%1) (PHY_Object[%1][PHY_Properties] & PHY_OBJECT_USED)
  137. #define PHY_IsObjectUsing3D(%1) (PHY_Object[%1][PHY_Properties] & PHY_OBJECT_MODE)
  138. #define PHY_IsObjectGhostWithObjects(%1) (PHY_Object[%1][PHY_Properties] & PHY_OBJECT_GHOST_OBJECTS)
  139. #define PHY_IsObjectGhostWithWalls(%1) (PHY_Object[%1][PHY_Properties] & PHY_OBJECT_GHOST_WALLS)
  140. #define PHY_IsObjectGhostWithCylinders(%1) (PHY_Object[%1][PHY_Properties] & PHY_OBJECT_GHOST_CYLINDERS)
  141. #define PHY_IsObjectCollidingWithPlayers(%1) (PHY_Object[%1][PHY_Properties] & PHY_OBJECT_PLAYER_COLLISIONS)
  142. #define PHY_IsObjectMoving(%1) (PHY_Object[%1][PHY_VX] != 0 || PHY_Object[%1][PHY_VY] != 0 || PHY_Object[%1][PHY_VZ] != 0)
  143. #define PHY_IsObjectRolling(%1) (PHY_Object[%1][PHY_Properties] & PHY_OBJECT_ROLL)
  144. #define PHY_GetObjectFriction(%1) (PHY_Object[%1][PHY_Friction])
  145. #define PHY_GetObjectAirResistance(%1) (PHY_Object[%1][PHY_AirResistance])
  146. #define PHY_GetObjectGravity(%1) (PHY_Object[%1][PHY_Gravity])
  147. #define PHY_GetObjectMode(%1) (PHY_Object[%1][PHY_Properties] & PHY_OBJECT_MODE)
  148.  
  149.  
  150. static
  151. cb_Connect;
  152.  
  153. public OnGameModeInit()
  154. {
  155. SetTimer("PHY_CoreTimer", PHY_TIMER_INTERVAL, true);
  156.  
  157. cb_Connect = funcidx("PHY_OnPlayerConnect") != -1;
  158. if(funcidx("PHY_OnGameModeInit") != -1)
  159. return CallLocalFunction("PHY_OnGameModeInit", "");
  160. return 1;
  161. }
  162.  
  163. public OnPlayerConnect(playerid)
  164. {
  165. PHY_Player[playerid][PHY_World] = 0;
  166.  
  167. if(cb_Connect)
  168. return CallLocalFunction("PHY_OnPlayerConnect", "i", playerid);
  169. return 1;
  170. }
  171.  
  172. forward PHY_CoreTimer();
  173. public PHY_CoreTimer()
  174. {
  175. new
  176. Float:x,
  177. Float:y,
  178. Float:z,
  179. Float:x1,
  180. Float:y1,
  181. Float:z1,
  182. Float:xclosest,
  183. Float:yclosest,
  184. Float:x2,
  185. Float:y2,
  186. Float:z2,
  187. Float:speed,
  188. Float:dx,
  189. Float:dy,
  190. Float:dz,
  191. Float:dist,
  192. Float:maxdist,
  193. Float:angle,
  194. Float:moveangle,
  195. Float:dvx,
  196. Float:dvy,
  197. Float:mag,
  198. Float:tmpvx1,
  199. Float:tmpvx2,
  200. Float:newvy1,
  201. Float:newvy2,
  202. Float:newvx1,
  203. Float:newvx2;
  204. foreach(ITER_Object, a)
  205. {
  206. if(PHY_Object[a][PHY_Properties] & PHY_OBJECT_USED)
  207. {
  208. GetObjectPos(a, x, y, z);
  209. x1 = x + PHY_Object[a][PHY_VX] * (PHY_TIMER_INTERVAL/1000.0);
  210. y1 = y + PHY_Object[a][PHY_VY] * (PHY_TIMER_INTERVAL/1000.0);
  211. if(PHY_GetObjectMode(a) == PHY_MODE_3D)
  212. {
  213. z1 = z + PHY_Object[a][PHY_VZ] * (PHY_TIMER_INTERVAL/1000.0);
  214.  
  215. if(z1 > PHY_Object[a][PHY_HighZBound])
  216. {
  217. if(PHY_Object[a][PHY_VZ] > 0)
  218. PHY_Object[a][PHY_VZ] = -PHY_Object[a][PHY_VZ] * PHY_Object[a][PHY_BoundConst];
  219. z1 = PHY_Object[a][PHY_HighZBound];
  220. }
  221. else if(z1 < PHY_Object[a][PHY_LowZBound])
  222. {
  223. if(PHY_Object[a][PHY_VZ] < 0)
  224. PHY_Object[a][PHY_VZ] = -PHY_Object[a][PHY_VZ] * PHY_Object[a][PHY_BoundConst];
  225. z1 = PHY_Object[a][PHY_LowZBound];
  226. }
  227. if(PHY_GetObjectGravity(a) != 0)
  228. {
  229. if(PHY_Object[a][PHY_VZ] > 0)
  230. {
  231. PHY_Object[a][PHY_VZ] -= PHY_Object[a][PHY_Gravity] * (PHY_TIMER_INTERVAL/1000.0);
  232. if(PHY_Object[a][PHY_VZ] < 0)
  233. PHY_Object[a][PHY_VZ] = 0;
  234. }
  235. else
  236. PHY_Object[a][PHY_VZ] -= PHY_Object[a][PHY_Gravity] * (PHY_TIMER_INTERVAL/1000.0);
  237. }
  238. }
  239. else
  240. z1 = z;
  241. if(PHY_IsObjectMoving(a))
  242. {
  243. if(!PHY_IsObjectGhostWithObjects(a))
  244. {
  245. foreach(ITER_Object, b)
  246. {
  247. if(a != b && PHY_Object[b][PHY_Properties] & PHY_OBJECT_USED && !PHY_IsObjectGhostWithObjects(b) && (!PHY_Object[a][PHY_World] || !PHY_Object[b][PHY_World] || PHY_Object[a][PHY_World] == PHY_Object[b][PHY_World]))
  248. {
  249. GetObjectPos(b, x2, y2, z2);
  250. dx = x1 - x2;
  251. dy = y1 - y2;
  252. dz = (PHY_GetObjectMode(a) == PHY_MODE_3D && PHY_GetObjectMode(b) == PHY_MODE_3D) ? (z1 - z2) : (0.0);
  253. dist = (dx * dx) + (dy * dy) + (dz * dz);
  254. maxdist = PHY_Object[a][PHY_Size] + PHY_Object[b][PHY_Size];
  255. if(dist < (maxdist * maxdist))
  256. {
  257. dvx = PHY_Object[a][PHY_VX] - PHY_Object[b][PHY_VX];
  258. dvy = PHY_Object[a][PHY_VY] - PHY_Object[b][PHY_VX];
  259. mag = dvx * dx + dvy * dy;
  260.  
  261. if(mag < 0.0)
  262. {
  263. angle = -atan2(dy, dx);
  264. tmpvx1 = PHY_Object[a][PHY_VX] * floatcos(angle, degrees) - PHY_Object[a][PHY_VY] * floatsin(angle, degrees);
  265. newvy1 = PHY_Object[a][PHY_VX] * floatsin(angle, degrees) + PHY_Object[a][PHY_VY] * floatcos(angle, degrees);
  266. tmpvx2 = PHY_Object[b][PHY_VX] * floatcos(angle, degrees) - PHY_Object[b][PHY_VY] * floatsin(angle, degrees);
  267. newvy2 = PHY_Object[b][PHY_VX] * floatsin(angle, degrees) + PHY_Object[b][PHY_VY] * floatcos(angle, degrees);
  268.  
  269. if(PHY_Object[a][PHY_Mass] == FLOAT_INFINITY)
  270. newvx2 = -tmpvx2;
  271. else if(PHY_Object[b][PHY_Mass] == FLOAT_INFINITY)
  272. newvx1 = -tmpvx1;
  273. else
  274. {
  275. newvx1 = ((PHY_Object[a][PHY_Mass] - PHY_Object[b][PHY_Mass]) * tmpvx1 + 2 * PHY_Object[b][PHY_Mass] * tmpvx2) / (PHY_Object[a][PHY_Mass] + PHY_Object[b][PHY_Mass]);
  276. newvx2 = ((PHY_Object[b][PHY_Mass] - PHY_Object[a][PHY_Mass]) * tmpvx2 + 2 * PHY_Object[a][PHY_Mass] * tmpvx1) / (PHY_Object[a][PHY_Mass] + PHY_Object[b][PHY_Mass]);
  277. }
  278.  
  279. angle = -angle;
  280. PHY_Object[a][PHY_VX] = newvx1 * floatcos(angle, degrees) - newvy1 * floatsin(angle, degrees);
  281. PHY_Object[a][PHY_VY] = newvx1 * floatsin(angle, degrees) + newvy1 * floatcos(angle, degrees);
  282. PHY_Object[b][PHY_VX] = newvx2 * floatcos(angle, degrees) - newvy2 * floatsin(angle, degrees);
  283. PHY_Object[b][PHY_VY] = newvx2 * floatsin(angle, degrees) + newvy2 * floatcos(angle, degrees);
  284.  
  285. CallLocalFunction("PHY_OnObjectCollideWithObject", "dd", a, b);
  286. }
  287. }
  288. }
  289. }
  290. }
  291. if(!PHY_IsObjectGhostWithWalls(a))
  292. {
  293. foreach(ITER_Wall, w)
  294. {
  295. if(PHY_Wall[w][PHY_Created])
  296. {
  297. if((!PHY_Object[a][PHY_World] || !PHY_Wall[w][PHY_World] || PHY_Object[a][PHY_World] == PHY_Wall[w][PHY_World]))
  298. {
  299. //dist = (y1 - PHY_Wall[w][PHY_M] * x1 - PHY_Wall[w][PHY_Q])/floatsqroot(1 + PHY_Wall[w][PHY_M] * PHY_Wall[w][PHY_M]);
  300. //dist = (PHY_Wall[w][PHY_A] * x1 + PHY_Wall[w][PHY_B] * y1 + PHY_Wall[w][PHY_C])/floatsqroot(PHY_Wall[w][PHY_A] * PHY_Wall[w][PHY_A] + PHY_Wall[w][PHY_B] * PHY_Wall[w][PHY_B]);
  301. angle = PHY_Wall[w][PHY_ANG];
  302. if(PHY_Wall[w][PHY_Z1] - PHY_Object[a][PHY_Size] < z1 < PHY_Wall[w][PHY_Z2] + PHY_Object[a][PHY_Size] &&
  303. (check_segment_intersection(PHY_Wall[w][PHY_X1], PHY_Wall[w][PHY_Y1], PHY_Wall[w][PHY_X2], PHY_Wall[w][PHY_Y2], x1, y1, PHY_Object[a][PHY_Size], xclosest, yclosest) || /* && floatabs(dist) < PHY_Object[a][PHY_Size]*/
  304. check_segment_intersection(PHY_Wall[w][PHY_X1], PHY_Wall[w][PHY_Y1], PHY_Wall[w][PHY_X2], PHY_Wall[w][PHY_Y2], (x + x1)/2, (y + y1)/2, PHY_Object[a][PHY_Size], xclosest, yclosest)))
  305. {
  306. //mag = y1 + PHY_Object[a][PHY_Size] * floatcos(-moveangle, degrees) - (x1 + PHY_Object[a][PHY_Size] * floatsin(-moveangle, degrees)) * PHY_Wall[w][PHY_M] - PHY_Wall[w][PHY_Q];
  307. //mag = PHY_Wall[w][PHY_A] * (x1 + PHY_Object[a][PHY_Size] * floatsin(-moveangle, degrees)) + PHY_Wall[w][PHY_B] * (y1 + PHY_Object[a][PHY_Size] * floatcos(-moveangle, degrees)) + PHY_Wall[w][PHY_C];
  308. //if((dist >= 0) ? (mag <= 0) : (mag >= 0))
  309. newvx1 = PHY_Wall[w][PHY_BounceConst] * (PHY_Object[a][PHY_VX] * floatcos(angle, degrees) - PHY_Object[a][PHY_VY] * floatsin(angle, degrees));
  310. newvy1 = -PHY_Wall[w][PHY_BounceConst] * (PHY_Object[a][PHY_VX] * floatsin(angle, degrees) + PHY_Object[a][PHY_VY] * floatcos(angle, degrees));
  311. angle = -angle;
  312. PHY_Object[a][PHY_VX] = newvx1 * floatcos(angle, degrees) - newvy1 * floatsin(angle, degrees);
  313. PHY_Object[a][PHY_VY] = newvx1 * floatsin(angle, degrees) + newvy1 * floatcos(angle, degrees);
  314.  
  315. angle = angle + (newvy1 > 0 ? 90.0 : -90.0);
  316. x1 = xclosest + (PHY_Object[a][PHY_Size] + 0.001) * floatcos(angle, degrees);
  317. y1 = yclosest + (PHY_Object[a][PHY_Size] + 0.001) * floatsin(angle, degrees);
  318.  
  319. CallLocalFunction("PHY_OnObjectCollideWithWall", "dd", a, w);
  320. }
  321. }
  322. }
  323. else
  324. Iter_SafeRemove(ITER_Wall, w, w);
  325. }
  326. }
  327. if(!PHY_IsObjectGhostWithCylinders(a))
  328. {
  329. foreach(ITER_Cylinder, c)
  330. {
  331. if(PHY_Cylinder[c][PHY_Created])
  332. {
  333. if((!PHY_Object[a][PHY_World] || !PHY_Cylinder[c][PHY_World] || PHY_Object[a][PHY_World] == PHY_Cylinder[c][PHY_World]))
  334. {
  335. if(PHY_Cylinder[c][PHY_Z1] - PHY_Object[a][PHY_Size] < z1 < PHY_Cylinder[c][PHY_Z2] + PHY_Object[a][PHY_Size])
  336. {
  337. x2 = PHY_Cylinder[c][PHY_X];
  338. y2 = PHY_Cylinder[c][PHY_Y];
  339. dx = x1 - x2;
  340. dy = y1 - y2;
  341. dist = (dx * dx) + (dy * dy);
  342. maxdist = PHY_Object[a][PHY_Size] + PHY_Cylinder[c][PHY_Size];
  343. if(dist < (maxdist * maxdist))
  344. {
  345. mag = PHY_Object[a][PHY_VX] * dx + PHY_Object[a][PHY_VY] * dy;
  346.  
  347. if(mag < 0.0)
  348. {
  349. angle = -atan2(dy, dx);
  350. newvx1 = -PHY_Cylinder[c][PHY_BounceConst] * (PHY_Object[a][PHY_VX] * floatcos(angle, degrees) - PHY_Object[a][PHY_VY] * floatsin(angle, degrees));
  351. newvy1 = PHY_Cylinder[c][PHY_BounceConst] * (PHY_Object[a][PHY_VX] * floatsin(angle, degrees) + PHY_Object[a][PHY_VY] * floatcos(angle, degrees));
  352.  
  353. angle = -angle;
  354. PHY_Object[a][PHY_VX] = newvx1 * floatcos(angle, degrees) - newvy1 * floatsin(angle, degrees);
  355. PHY_Object[a][PHY_VY] = newvx1 * floatsin(angle, degrees) + newvy1 * floatcos(angle, degrees);
  356.  
  357. CallLocalFunction("PHY_OnObjectCollideWithCylinder", "dd", a, c);
  358. }
  359. }
  360. }
  361. }
  362. }
  363. else
  364. Iter_SafeRemove(ITER_Cylinder, c, c);
  365. }
  366. }
  367. if(PHY_IsObjectCollidingWithPlayers(a))
  368. {
  369. foreach(Player, i)
  370. {
  371. if((!PHY_Object[a][PHY_World] || !PHY_Player[i][PHY_World] || PHY_Object[a][PHY_World] == PHY_Player[i][PHY_World]))
  372. {
  373. GetPlayerPos(i, x2, y2, z2);
  374.  
  375. if(z2 - PHY_Object[a][PHY_PlayerLowZ] - PHY_Object[a][PHY_Size] < z1 < z2 + PHY_Object[a][PHY_PlayerHighZ] + PHY_Object[a][PHY_Size])
  376. {
  377. dx = x1 - x2;
  378. dy = y1 - y2;
  379. dist = (dx * dx) + (dy * dy);
  380. maxdist = PHY_Object[a][PHY_Size] + PHY_Object[a][PHY_PlayerDist];
  381. if(dist < (maxdist * maxdist))
  382. {
  383. mag = PHY_Object[a][PHY_VX] * dx + PHY_Object[a][PHY_VY] * dy;
  384.  
  385. if(mag < 0.0)
  386. {
  387. angle = -atan2(dy, dx);
  388. newvx1 = -PHY_Object[a][PHY_PlayerConst] * (PHY_Object[a][PHY_VX] * floatcos(angle, degrees) - PHY_Object[a][PHY_VY] * floatsin(angle, degrees));
  389. newvy1 = PHY_Object[a][PHY_PlayerConst] * (PHY_Object[a][PHY_VX] * floatsin(angle, degrees) + PHY_Object[a][PHY_VY] * floatcos(angle, degrees));
  390.  
  391. angle = -angle;
  392. PHY_Object[a][PHY_VX] = newvx1 * floatcos(angle, degrees) - newvy1 * floatsin(angle, degrees);
  393. PHY_Object[a][PHY_VY] = newvx1 * floatsin(angle, degrees) + newvy1 * floatcos(angle, degrees);
  394.  
  395. CallLocalFunction("PHY_OnObjectCollideWithPlayer", "dd", a, i);
  396. }
  397. }
  398. }
  399. }
  400. }
  401. }
  402. moveangle = atan2(PHY_Object[a][PHY_VY], PHY_Object[a][PHY_VX]) - 90.0;
  403. speed = floatsqroot(PHY_Object[a][PHY_VX] * PHY_Object[a][PHY_VX] + PHY_Object[a][PHY_VY] * PHY_Object[a][PHY_VY]);
  404. if(PHY_GetObjectFriction(a) != 0 && z1 == PHY_Object[a][PHY_LowZBound])
  405. {
  406. speed -= PHY_Object[a][PHY_Friction] * (PHY_TIMER_INTERVAL/1000.0);
  407. if(speed < 0.001)
  408. speed = 0;
  409. PHY_Object[a][PHY_VX] = speed * floatsin(-moveangle, degrees);
  410. PHY_Object[a][PHY_VY] = speed * floatcos(-moveangle, degrees);
  411. }
  412. if(PHY_GetObjectAirResistance(a) != 0)
  413. {
  414. PHY_Object[a][PHY_VX] -= PHY_Object[a][PHY_VX] * PHY_Object[a][PHY_AirResistance] * (PHY_TIMER_INTERVAL/1000.0);
  415. PHY_Object[a][PHY_VY] -= PHY_Object[a][PHY_VY] * PHY_Object[a][PHY_AirResistance] * (PHY_TIMER_INTERVAL/1000.0);
  416. PHY_Object[a][PHY_VZ] -= PHY_Object[a][PHY_VZ] * PHY_Object[a][PHY_AirResistance] * (PHY_TIMER_INTERVAL/1000.0);
  417. }
  418. if(PHY_IsObjectRolling(a) && speed > 0.0)
  419. PHY_ApplyRotation(a, speed, moveangle);
  420. }
  421.  
  422. PHY_Object[a][PHY_VX] += PHY_Object[a][PHY_AX];
  423. PHY_Object[a][PHY_VY] += PHY_Object[a][PHY_AY];
  424. PHY_Object[a][PHY_VZ] += PHY_Object[a][PHY_AZ];
  425.  
  426. SetObjectPos(a, x1, y1, z1);
  427. CallLocalFunction("PHY_OnObjectUpdate", "d", a);
  428. }
  429. else
  430. Iter_SafeRemove(ITER_Object, a, a);
  431. }
  432. return 1;
  433. }
  434.  
  435.  
  436. /* Starts using physics for objectid.
  437. modelid - object's modelid, used to get its size with modelsizes include.
  438. mass - object's mass, it is like its weight and is used in collisions.
  439. size - object's sphere radius, taken from modelsizes.inc by default.
  440. mode - PHY_MODE_3D or PHY_MODE_2D. */
  441. stock PHY_InitObject(objectid, modelid = 0, Float:mass = 1.0, Float:size = FLOAT_NAN, mode = PHY_MODE_3D)
  442. {
  443. if(IsValidObject(objectid))
  444. {
  445. PHY_Object[objectid][PHY_Properties] = PHY_OBJECT_USED | (mode ? PHY_OBJECT_MODE : 0);
  446. PHY_Object[objectid][PHY_Mass] = mass;
  447. PHY_Object[objectid][PHY_World] = 0;
  448. PHY_Object[objectid][PHY_VX] = 0;
  449. PHY_Object[objectid][PHY_VY] = 0;
  450. PHY_Object[objectid][PHY_VZ] = 0;
  451. PHY_Object[objectid][PHY_Gravity] = 0;
  452. new
  453. Float:unused;
  454. GetObjectPos(objectid, unused, unused, PHY_Object[objectid][PHY_LowZBound]);
  455. PHY_Object[objectid][PHY_HighZBound] = FLOAT_INFINITY;
  456. PHY_Object[objectid][PHY_BoundConst] = 0;
  457.  
  458. if(size != size)
  459. {
  460. if(modelid)
  461. PHY_Object[objectid][PHY_Size] = GetColSphereRadius(modelid);
  462. }
  463. else
  464. PHY_Object[objectid][PHY_Size] = size;
  465.  
  466. Iter_Add(ITER_Object, objectid);
  467. return 1;
  468. }
  469. return 0;
  470. }
  471.  
  472. /* Stops using physics for objectid (doesn't destroy it). */
  473. stock PHY_DeleteObject(objectid)
  474. {
  475. PHY_Object[objectid][PHY_Properties] = 0;
  476. // Iter_Remove(ITER_Object, objectid);
  477. return 1;
  478. }
  479.  
  480. /* Moves the object with vx, vy, vz velocities. */
  481. stock PHY_SetObjectVelocity(objectid, Float:vx, Float:vy, Float:vz = 0.0)
  482. {
  483. if(PHY_Object[objectid][PHY_Properties] & PHY_OBJECT_USED)
  484. {
  485. PHY_Object[objectid][PHY_VX] = vx;
  486. PHY_Object[objectid][PHY_VY] = vy;
  487. PHY_Object[objectid][PHY_VZ] = vz;
  488. return 1;
  489. }
  490. return 0;
  491. }
  492.  
  493. /* Self-explanatory */
  494. stock PHY_GetObjectVelocity(objectid, &Float:vx, &Float:vy, &Float:vz)
  495. {
  496. if(PHY_Object[objectid][PHY_Properties] & PHY_OBJECT_USED)
  497. {
  498. vx = PHY_Object[objectid][PHY_VX];
  499. vy = PHY_Object[objectid][PHY_VY];
  500. vz = PHY_Object[objectid][PHY_VZ];
  501. return 1;
  502. }
  503. return 0;
  504. }
  505.  
  506. /* Sets the object's acceleration. */
  507. stock PHY_SetObjectAcceleration(objectid, Float:ax, Float:ay, Float:az = 0.0)
  508. {
  509. if(PHY_Object[objectid][PHY_Properties] & PHY_OBJECT_USED)
  510. {
  511. PHY_Object[objectid][PHY_AX] = ax;
  512. PHY_Object[objectid][PHY_AY] = ay;
  513. PHY_Object[objectid][PHY_AZ] = az;
  514. return 1;
  515. }
  516. return 0;
  517. }
  518.  
  519. /* Self-explanatory */
  520. stock PHY_GetObjectAcceleration(objectid, &Float:ax, &Float:ay, &Float:az)
  521. {
  522. if(PHY_Object[objectid][PHY_Properties] & PHY_OBJECT_USED)
  523. {
  524. ax = PHY_Object[objectid][PHY_AX];
  525. ay = PHY_Object[objectid][PHY_AY];
  526. az = PHY_Object[objectid][PHY_AZ];
  527. return 1;
  528. }
  529. return 0;
  530. }
  531.  
  532. /* Self-explanatory */
  533. stock PHY_GetObjectSpeed(objectid, &Float:speed, _3D = 0)
  534. {
  535. if(PHY_Object[objectid][PHY_Properties] & PHY_OBJECT_USED)
  536. {
  537. speed = floatsqroot(PHY_Object[objectid][PHY_VX] * PHY_Object[objectid][PHY_VX] + PHY_Object[objectid][PHY_VY] * PHY_Object[objectid][PHY_VY] + _3D ? (PHY_Object[objectid][PHY_VZ] * PHY_Object[objectid][PHY_VZ]) : 0.0);
  538. return 1;
  539. }
  540. return 0;
  541. }
  542.  
  543. /* Self-explanatory */
  544. stock PHY_GetObjectMoveAngle(objectid, &Float:moveangle)
  545. {
  546. if(PHY_Object[objectid][PHY_Properties] & PHY_OBJECT_USED)
  547. {
  548. moveangle = atan2(PHY_Object[objectid][PHY_VY], PHY_Object[objectid][PHY_VX]) - 90.0;
  549. return 1;
  550. }
  551. return 0;
  552. }
  553.  
  554. /* Starts rolling the object when it moves of toggle = 1 or stops if toggle = 0. */
  555. stock PHY_RollObject(objectid, toggle = 1)
  556. {
  557. if(PHY_Object[objectid][PHY_Properties] & PHY_OBJECT_USED)
  558. {
  559. if(toggle)
  560. PHY_Object[objectid][PHY_Properties] |= PHY_OBJECT_ROLL;
  561. else
  562. PHY_Object[objectid][PHY_Properties] &= ~PHY_OBJECT_ROLL;
  563. return 1;
  564. }
  565. return 0;
  566. }
  567.  
  568. /* Applies friction to the object when it moves on the floor. */
  569. stock PHY_SetObjectFriction(objectid, Float:friction)
  570. {
  571. if(PHY_Object[objectid][PHY_Properties] & PHY_OBJECT_USED)
  572. {
  573. if(friction >= 0.0)
  574. PHY_Object[objectid][PHY_Friction] = friction;
  575. return 1;
  576. }
  577. return 0;
  578. }
  579.  
  580. /* Applies air resistance to the object when it moves. */
  581. stock PHY_SetObjectAirResistance(objectid, Float:resistance)
  582. {
  583. if(PHY_Object[objectid][PHY_Properties] & PHY_OBJECT_USED)
  584. {
  585. if(0.0 <= resistance <= 1.0)
  586. PHY_Object[objectid][PHY_AirResistance] = resistance;
  587. return 1;
  588. }
  589. return 0;
  590. }
  591.  
  592. /* Limits the object's Z position.
  593. low - The lowest Z that the object can have (you can use FLOAT_NEG_INFINITY). If it is set to NaN it doesn't change.
  594. high - The highest Z that the object can have (you can use FLOAT_INFINITY). If it is set to NaN it doesn't change.
  595. (When you use PHY_InitObject lowest Z is set to the current object's Z and highest Z to FLOAT_INFINITY.
  596. constant - It should be from 0.0 to 1.0. If it is 1.0 the object doesn't lose velocity,
  597. if it is 0.0 the object stops when it bounces. It could be a middle ground.*/
  598. stock PHY_SetObjectZBound(objectid, Float:low = FLOAT_NAN, Float:high = FLOAT_NAN, Float:constant = 0.0)
  599. {
  600. if(PHY_Object[objectid][PHY_Properties] & PHY_OBJECT_USED)
  601. {
  602. if(low == low)
  603. PHY_Object[objectid][PHY_LowZBound] = low;
  604. if(high == high)
  605. PHY_Object[objectid][PHY_HighZBound] = high;
  606. PHY_Object[objectid][PHY_BoundConst] = constant;
  607. return 1;
  608. }
  609. return 0;
  610. }
  611.  
  612. /* Sets the gravity's acceleration that the object is subjected to. */
  613. stock PHY_SetObjectGravity(objectid, Float:gravity)
  614. {
  615. if(PHY_Object[objectid][PHY_Properties] & PHY_OBJECT_USED)
  616. {
  617. PHY_Object[objectid][PHY_Gravity] = gravity;
  618. return 1;
  619. }
  620. return 0;
  621. }
  622.  
  623. /* Object and walls collide only if the are in the same world or one of them is in the world 0 (default). */
  624. stock PHY_SetObjectWorld(objectid, world)
  625. {
  626. if(PHY_Object[objectid][PHY_Properties] & PHY_OBJECT_USED)
  627. {
  628. PHY_Object[objectid][PHY_World] = world;
  629. return 1;
  630. }
  631. return 0;
  632. }
  633.  
  634. /* Toggles object's collisions with players.
  635. - constant - It should be from 0.0 to 1.0. If it is 1.0 the object doesn't lose velocity,
  636. if it is 0.0 the object stops when it bounces. It could be a middle ground.
  637. - distoffset - The distance at which the object collides with the player.
  638. - zoffsetlow/zoffsethigh - The max Z distance (downward/upward) at which the object collides with the player. */
  639. stock PHY_ToggleObjectPlayerColls(objectid, toggle = 1, Float:constant = 1.0, Float:distoffset = 0.8, Float:zoffsetlow = 1.0, Float:zoffsethigh = 1.0)
  640. {
  641. if(PHY_Object[objectid][PHY_Properties] & PHY_OBJECT_USED)
  642. {
  643. if(toggle)
  644. {
  645. PHY_Object[objectid][PHY_Properties] |= PHY_OBJECT_PLAYER_COLLISIONS;
  646. PHY_Object[objectid][PHY_PlayerConst] = constant;
  647. PHY_Object[objectid][PHY_PlayerDist] = distoffset;
  648. PHY_Object[objectid][PHY_PlayerLowZ] = zoffsetlow;
  649. PHY_Object[objectid][PHY_PlayerHighZ] = zoffsethigh;
  650. }
  651. else
  652. PHY_Object[objectid][PHY_Properties] &= ~PHY_OBJECT_PLAYER_COLLISIONS;
  653. return 1;
  654. }
  655. return 0;
  656. }
  657.  
  658. /* Used internally to rotate the objects */
  659. stock PHY_ApplyRotation(objectid, Float:speed, Float:moveangle)
  660. {
  661. new
  662. Float:rx, Float:ry, Float:rz;
  663. GetObjectRot(objectid, rx, ry, rz);
  664. rx -= speed * (PHY_TIMER_INTERVAL/1000.0) * (180.0/3.14159) / PHY_Object[objectid][PHY_Size];
  665. if(rx < 0.0)
  666. rx += 360.0;
  667. rz = moveangle;
  668. //PHY_Roll(rx, ry, rz, PHY_Object[a][PHY_VX], PHY_Object[a][PHY_VY], ((speed * PHY_TIMER_INTERVAL)/1000) * (180/3.14159) / PHY_Object[a][PHY_Size]);
  669. SetObjectRot(objectid, rx, ry, rz);
  670. return 1;
  671. }
  672.  
  673. /* Creates a collision wall (straight line) from A(x1, y1) to B(x2, y2).
  674. constant should be from 0.0 to 1.0. If it is 1.0 the object doesn't lose velocity,
  675. if it is 0.0 the object stops when it collides.
  676. low is the lowest wall's Z, high is the highest. If they're set to default the wall is like infinitely high.*/
  677. stock PHY_CreateWall(Float:x1, Float:y1, Float:x2, Float:y2, Float:constant = 1.0, Float:low = FLOAT_NEG_INFINITY, Float:high = FLOAT_INFINITY)
  678. {
  679. new
  680. i = Iter_Free(ITER_Wall);
  681. if(i != -1)
  682. {
  683. if(!PHY_Wall[i][PHY_Created])
  684. {
  685. PHY_Wall[i][PHY_Created] = 1;
  686. PHY_Wall[i][PHY_World] = 0;
  687. PHY_Wall[i][PHY_X1] = x1;
  688. PHY_Wall[i][PHY_Y1] = y1;
  689. PHY_Wall[i][PHY_X2] = x2;
  690. PHY_Wall[i][PHY_Y2] = y2;
  691. PHY_Wall[i][PHY_Z1] = low;
  692. PHY_Wall[i][PHY_Z2] = high;
  693. PHY_Wall[i][PHY_BounceConst] = constant;
  694. PHY_Wall[i][PHY_ANG] = atan2(y1 - y2, x1 - x2);
  695. /*PHY_Wall[i][PHY_A] = -(y2 - y1);
  696. PHY_Wall[i][PHY_B] = (x2 - x1);
  697. PHY_Wall[i][PHY_C] = (y2 - y1) * x1 - (x2 - x1) * y1;*/
  698. //PHY_Wall[i][PHY_Q] = -((y2 - y1) * x1)/(x2 - x1) + y1;
  699.  
  700. Iter_Add(ITER_Wall, i);
  701. return i;
  702. }
  703. }
  704. return -1;
  705. }
  706.  
  707. /* Creates four walls that form an area. Works like IsPlayerInArea. */
  708. stock PHY_CreateArea(Float:minX, Float:minY, Float:maxX, Float:maxY, Float:constant = 1.0, Float:low = FLOAT_NEG_INFINITY, Float:high = FLOAT_INFINITY)
  709. {
  710. PHY_CreateWall(minX, minY, minX, maxY, constant, low, high);
  711. PHY_CreateWall(minX, maxY, maxX, maxY, constant, low, high);
  712. PHY_CreateWall(maxX, maxY, maxX, minY, constant, low, high);
  713. PHY_CreateWall(maxX, minY, minX, minY, constant, low, high);
  714. }
  715.  
  716. /* Self-explanatory */
  717. stock PHY_DestroyWall(wallid)
  718. {
  719. PHY_Wall[wallid][PHY_Created] = 0;
  720. // Iter_Remove(ITER_Wall, wallid);
  721. return 1;
  722. }
  723.  
  724. /* See PHY_SetObjectWorld(objectid, world). */
  725. stock PHY_SetWallWorld(wallid, world)
  726. {
  727. if(PHY_Wall[wallid][PHY_Created])
  728. {
  729. PHY_Wall[wallid][PHY_World] = world;
  730. return 1;
  731. }
  732. return 0;
  733. }
  734.  
  735. /* Creates a collision cylinder at position x, y.
  736. constant should be from 0.0 to 1.0. If it is 1.0 the object doesn't lose velocity,
  737. if it is 0.0 the object stops when it collides.
  738. low is the lowest cylinder's Z, high is the highest. If they're set to default the cylinder is like infinitely high.*/
  739. stock PHY_CreateCylinder(Float:x, Float:y, Float:size, Float:constant = 1.0, Float:low = FLOAT_NEG_INFINITY, Float:high = FLOAT_INFINITY)
  740. {
  741. new
  742. i = Iter_Free(ITER_Cylinder);
  743. if(i != -1)
  744. {
  745. if(!PHY_Cylinder[i][PHY_Created])
  746. {
  747. PHY_Cylinder[i][PHY_Created] = 1;
  748. PHY_Cylinder[i][PHY_World] = 0;
  749. PHY_Cylinder[i][PHY_X] = x;
  750. PHY_Cylinder[i][PHY_Y] = y;
  751. PHY_Cylinder[i][PHY_Size] = size;
  752. PHY_Cylinder[i][PHY_Z1] = low;
  753. PHY_Cylinder[i][PHY_Z2] = high;
  754. PHY_Cylinder[i][PHY_BounceConst] = constant;
  755.  
  756. Iter_Add(ITER_Cylinder, i);
  757. return i;
  758. }
  759. }
  760. return -1;
  761. }
  762.  
  763. /* Self-explanatory */
  764. stock PHY_DestroyCylinder(cylinderid)
  765. {
  766. PHY_Cylinder[cylinderid][PHY_Created] = 0;
  767. // Iter_Remove(ITER_Cylinder, cylinderid);
  768. return 1;
  769. }
  770.  
  771. /* See PHY_SetObjectWorld(objectid, world). */
  772. stock PHY_SetCylinderWorld(cylinderid, world)
  773. {
  774. if(PHY_Cylinder[cylinderid][PHY_Created])
  775. {
  776. PHY_Cylinder[cylinderid][PHY_World] = world;
  777. return 1;
  778. }
  779. return 0;
  780. }
  781.  
  782. /* See PHY_SetObjectWorld(objectid, world). */
  783. stock PHY_SetPlayerWorld(playerid, world)
  784. {
  785. PHY_Player[playerid][PHY_World] = world;
  786. return 1;
  787. }
  788.  
  789. /* Privates */
  790.  
  791. stock Float:vectordotp(Float:v1x, Float:v1y, Float:v2x, Float:v2y)
  792. return (v1x * v2x + v1y * v2y);
  793.  
  794. stock check_segment_intersection(Float:x1, Float:y1, Float:x2, Float:y2, Float:xc, Float:yc, Float:r, &Float:x, &Float:y)
  795. {
  796. new Float:v1[2];
  797. new Float:v2[2];
  798. v1[0] = x2 - x1;
  799. v1[1] = y2 - y1;
  800. v2[0] = xc - x1;
  801. v2[1] = yc - y1;
  802. new Float:v1_len = floatsqroot(v1[0] * v1[0] + v1[1] * v1[1]);
  803. v1[0] /= v1_len;
  804. v1[1] /= v1_len;
  805. new Float:proj = vectordotp(v2[0], v2[1], v1[0], v1[1]);
  806. x = proj * v1[0] + x1;
  807. y = proj * v1[1] + y1;
  808. return ((0 - r < proj < v1_len + r) && ((x - xc) * (x - xc) + (y - yc) * (y - yc) < (r * r)));
  809. }
  810.  
  811. /* Function to make a better ball rolling, not used because it doesn't work well. */
  812. stock PHY_Roll(&Float:x, &Float:y, &Float:z, Float:dx, Float:dy, Float:speed)
  813. {
  814. new Float:q_roll[4];
  815. new Float:vx, Float:vy, Float:vz;
  816. vectorcrossp(dx, dy, 0.0, 0.0, 0.0, 1.0, vx, vy, vz);
  817. QuatFromAxisAngle(vx, vy, vz, -speed, q_roll[0], q_roll[1], q_roll[2], q_roll[3]);
  818.  
  819. new Float:q_rot[4];
  820. EulerToQuaternion(x, y, z, q_rot[0], q_rot[1], q_rot[2], q_rot[3]);
  821.  
  822. new Float:q_res[4];
  823. QuatMultiply(q_roll[0], q_roll[1], q_roll[2], q_roll[3], q_rot[0], q_rot[1], q_rot[2], q_rot[3], q_res[0], q_res[1], q_res[2], q_res[3]);
  824.  
  825. QuaternionToEuler(q_res[0], q_res[1], q_res[2], q_res[3], x, y, z);
  826. }
  827.  
  828. stock QuatMultiply(Float:w1, Float:x1, Float:y1, Float:z1, Float:w2, Float:x2, Float:y2, Float:z2, &Float:q_w, &Float:q_x, &Float:q_y, &Float:q_z)
  829. {
  830. q_w = w1*w2 - x1*x2 - y1*y2 - z1*z2;
  831. q_x = w1*x2 + x1*w2 + y1*z2 - z1*y2;
  832. q_y = w1*y2 - x1*z2 + y1*w2 + z1*x2;
  833. q_z = w1*z2 + x1*y2 - y1*x2 + z1*w2;
  834.  
  835. QuatNormalize(q_w, q_x, q_y, q_z);
  836. }
  837.  
  838. stock QuatFromAxisAngle(Float:x, Float:y, Float:z, Float:angle, &Float:q_w, &Float:q_x, &Float:q_y, &Float:q_z)
  839. {
  840. new
  841. Float:omega,
  842. Float:s;
  843.  
  844. s = floatsqroot(x*x + y*y + z*z);
  845.  
  846. if (s > 0.01)
  847. {
  848.  
  849. x /= s;
  850. y /= s;
  851. z /= s;
  852.  
  853. omega = 0.5 * angle;
  854. s = floatsin(omega, degrees);
  855.  
  856. q_x = s*x;
  857. q_y = s*y;
  858. q_z = s*z;
  859. q_w = floatcos(omega, degrees);
  860. }
  861. else
  862. {
  863. q_x = 0.0;
  864. q_y = 0.0;
  865. q_z = 0.0;
  866. q_w = 1.0;
  867. }
  868.  
  869. QuatNormalize(q_w, q_x, q_y, q_z);
  870. }
  871.  
  872. stock QuatNormalize(&Float:q_w, &Float:q_x, &Float:q_y, &Float:q_z)
  873. {
  874. new Float:magnitude = floatsqroot(q_w*q_w + q_x*q_x + q_y*q_y + q_z*q_z);
  875. if (magnitude == 0.0)
  876. {
  877. q_w = 1.0;
  878. q_x = 0.0;
  879. q_y = 0.0;
  880. q_z = 0.0;
  881. }
  882. else
  883. {
  884. q_w /= magnitude;
  885. q_x /= magnitude;
  886. q_y /= magnitude;
  887. q_z /= magnitude;
  888. }
  889. }
  890.  
  891. stock EulerToQuaternion(Float:z, Float:x, Float:y, &Float:q_w, &Float:q_x, &Float:q_y, &Float:q_z)
  892. {
  893. new Float:c1 = floatcos(x, degrees);
  894. new Float:s1 = floatsin(x, degrees);
  895. new Float:c2 = floatcos(y, degrees);
  896. new Float:s2 = floatsin(y, degrees);
  897. new Float:c3 = floatcos(z, degrees);
  898. new Float:s3 = floatsin(z, degrees);
  899. q_w = floatsqroot(1.0 + c1 * c2 + c1*c3 - s1 * s2 * s3 + c2*c3) / 2.0;
  900. new Float:w4 = (4.0 * q_w);
  901. q_x = (c2 * s3 + c1 * s3 + s1 * s2 * c3) / w4 ;
  902. q_y = (s1 * c2 + s1 * c3 + c1 * s2 * s3) / w4 ;
  903. q_z = (-s1 * s3 + c1 * s2 * c3 +s2) / w4 ;
  904.  
  905. QuatNormalize(q_w, q_x, q_y, q_z);
  906. }
  907.  
  908. stock QuaternionToEuler(Float:q_w, Float:q_x, Float:q_y, Float:q_z, &Float:z, &Float:x, &Float:y)
  909. {
  910. new Float:test = q_x*q_y + q_z*q_w;
  911. if (test > 0.499) { // singularity at north pole
  912. x = 2 * atan2(q_x,q_w);
  913. y = 90.0;
  914. z = 0;
  915. return;
  916. }
  917. if (test < -0.499) { // singularity at south pole
  918. x = -2 * atan2(q_x,q_w);
  919. y = -90.0;
  920. z = 0;
  921. return;
  922. }
  923. new Float:sqx = q_x*q_x;
  924. new Float:sqy = q_y*q_y;
  925. new Float:sqz = q_z*q_z;
  926. x = atan2(2*q_y*q_w-2*q_x*q_z , 1 - 2*sqy - 2*sqz);
  927. y = asin(2*test);
  928. z = atan2(2*q_x*q_w-2*q_y*q_z , 1 - 2*sqx - 2*sqz);
  929. }
  930.  
  931. stock vectorcrossp(Float:v1x, Float:v1y, Float:v1z, Float:v2x, Float:v2y, Float:v2z, &Float:c1, &Float:c2, &Float:c3)
  932. {
  933. c1 = (v1y * v2z) - (v1z * v2y),
  934. c2 = (v1z * v2x) - (v1x * v2z),
  935. c3 = (v1x * v2y) - (v1y * v2x);
  936. }
  937.  
  938.  
  939. #if defined _ALS_OnGameModeInit
  940. #undef OnGameModeInit
  941. #else
  942. #define _ALS_OnGameModeInit
  943. #endif
  944. #define OnGameModeInit PHY_OnGameModeInit
  945.  
  946. forward OnGameModeInit();
  947.  
  948.  
  949. #if defined _ALS_OnPlayerConnect
  950. #undef OnPlayerConnect
  951. #else
  952. #define _ALS_OnPlayerConnect
  953. #endif
  954. #define OnPlayerConnect PHY_OnPlayerConnect
  955.  
  956. forward OnPlayerConnect(playerid);
Advertisement
Add Comment
Please, Sign In to add comment