samp-ships.inc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. /**--------------------------------------------------------------------------**\
  2. ====================================
  3. samp-ships - background moving ships
  4. ====================================
  5. Author:
  6. Simon
  7. https://github.com/SimonItaly
  8. http://forum.sa-mp.com/member.php?u=84139
  9. Description:
  10. This include aims to create cargo ships passing in background
  11. for aestetic purpose by assigning them to custom routes.
  12. Legal:
  13. Version: MPL 1.1
  14. The contents of this file are subject to the Mozilla Public License Version
  15. 1.1 (the "License"); you may not use this file except in compliance with
  16. the License. You may obtain a copy of the License at
  17. http://www.mozilla.org/MPL
  18. Version:
  19. 1.0
  20. Thanks:
  21. adri1, Pottus: (see AttachObjectToObjectEx)
  22. Requirements:
  23. https://github.com/samp-incognito/samp-streamer-plugin
  24. https://github.com/karimcambridge/SAMP-foreach
  25. (or https://github.com/Misiur/YSI-Includes)
  26. https://github.com/Zeex/pawn
  27. Changelog:
  28. 2017/10/XX:
  29. First version.
  30. Functions:
  31. Stock:
  32. CreateShip
  33. SetShipBodyMaterial
  34. SetShipContainerMaterial
  35. DestroyShip
  36. CreateRoute
  37. DestroyRoute
  38. StartRouteForShip
  39. StopRouteForShip
  40. Static:
  41. absoluteangle
  42. GetAngleToPoint
  43. GetDistanceBetweenPoints_Ships
  44. GetXYInDirection
  45. AttachObjectToObjectEx
  46. EDIT_FloatEulerFix
  47. EDIT_FloatGetRemainder
  48. EDIT_FloatRemainder
  49. Public:
  50. ship_route_execute
  51. ship_rot
  52. Callbacks:
  53. OnShipRouteCompleted
  54. Iterators:
  55. Ship
  56. Route
  57. Compile options:
  58. DEBUG_SHIP_INC
  59. SHIP_STREAMER_SD
  60. SHIP_STREAMER_DD
  61. MAX_SHIPS
  62. MAX_ROUTES
  63. MAX_ROUTE_POINTS
  64. SHIP_ROT_STEP
  65. SHIP_MOV_SPEED
  66. SHIP_TIMER_STEP
  67. \**--------------------------------------------------------------------------**/
  68. #include <streamer>
  69. #tryinclude <YSI\y_iterate>
  70. #if !defined _Y_ITERATE_LOCAL_VERSION
  71. #include <foreach>
  72. #endif
  73. #if !defined SHIP_STREAMER_SD
  74. #define SHIP_STREAMER_SD 1000.0
  75. #endif
  76. #if !defined SHIP_STREAMER_DD
  77. #define SHIP_STREAMER_DD 1000.0
  78. #endif
  79. #if !defined MAX_SHIPS
  80. #define MAX_SHIPS 10
  81. #endif
  82. #if !defined MAX_ROUTES
  83. #define MAX_ROUTES 5
  84. #endif
  85. #if !defined MAX_ROUTE_POINTS
  86. #define MAX_ROUTE_POINTS 10
  87. #endif
  88. #define SHIP_ROT_STEP 0.1
  89. #define SHIP_MOV_SPEED 5.0
  90. #define SHIP_TIMER_STEP 15
  91. //==============================================================================
  92. static Float:absoluteangle(Float:a)
  93. {
  94. while(a < 0.0) a += 360.0;
  95. while(a > 360.0) a -= 360.0;
  96. return a;
  97. }
  98. static Float:GetAngleToPoint(Float:fPointX, Float:fPointY, Float:fDestX, Float:fDestY)
  99. {
  100. return absoluteangle(-(90-(atan2((fDestY - fPointY), (fDestX - fPointX)))));
  101. }
  102. static Float:GetDistanceBetweenPoints_Ships(Float:x1, Float:y1, Float:z1, Float:x2, Float:y2, Float:z2)
  103. {
  104. return VectorSize(x1-x2, y1-y2, z1-z2);
  105. }
  106. //==============================================================================
  107. enum E_SHIP_OFFSET
  108. {
  109. shipModelid,
  110. Float:shipX,
  111. Float:shipY,
  112. Float:shipZ,
  113. Float:shipSD,
  114. Float:shipDD
  115. }
  116. static const ship_offset[][E_SHIP_OFFSET] =
  117. {
  118. { 10231, -0.918, -1.5101, 1.47747, SHIP_STREAMER_SD, SHIP_STREAMER_DD }, //Ship cargo
  119. { 10229, -0.2481, -1.402, -1.15429, STREAMER_OBJECT_SD, STREAMER_OBJECT_DD }, //Ship bits
  120. { 2944, 47.2517, 1.2108, 4.439, STREAMER_OBJECT_SD, STREAMER_OBJECT_DD } //Ship door
  121. };
  122. enum E_SHIP_INFO
  123. {
  124. ship_part[sizeof(ship_offset)+1],
  125. ship_route,
  126. Float:ship_rot_step,
  127. Float:ship_mov_speed,
  128. ship_timer_step
  129. }
  130. // ship_info[MAX_SHIPS][E_SHIP_INFO]
  131. static
  132. ship_info[10][E_SHIP_INFO] =
  133. {
  134. { {0,0,0,0}, -1, 0.0, 0.0 },
  135. { {0,0,0,0}, -1, 0.0, 0.0 },
  136. { {0,0,0,0}, -1, 0.0, 0.0 },
  137. { {0,0,0,0}, -1, 0.0, 0.0 },
  138. { {0,0,0,0}, -1, 0.0, 0.0 },
  139. { {0,0,0,0}, -1, 0.0, 0.0 },
  140. { {0,0,0,0}, -1, 0.0, 0.0 },
  141. { {0,0,0,0}, -1, 0.0, 0.0 },
  142. { {0,0,0,0}, -1, 0.0, 0.0 },
  143. { {0,0,0,0}, -1, 0.0, 0.0 }
  144. };
  145. static
  146. Float:route_info[MAX_ROUTES][MAX_ROUTE_POINTS][2],
  147. route_lenght[MAX_ROUTES];
  148. //==============================================================================
  149. forward OnShipRouteCompleted(ship_id, route_id, steps);
  150. new
  151. Iterator:Ship<MAX_SHIPS>;
  152. new
  153. Iterator:Route<MAX_ROUTES>;
  154. /**--------------------------------------------------------------------------**\
  155. <summary>CreateShip</summary>
  156. <param name="x">-</param>
  157. <param name="y">-</param>
  158. <param name="z">-</param>
  159. <param name="rot">-</param>
  160. <param name="rot_step">-</param>
  161. <param name="mov_speed">-</param>
  162. <returns>
  163. -1 on fail, the id of the ship otherwise.
  164. </returns>
  165. <remarks>
  166. -
  167. </remarks>
  168. \**--------------------------------------------------------------------------**/
  169. stock CreateShip(Float:x, Float:y, Float:z, Float:rot,
  170. Float:rot_step = SHIP_ROT_STEP,
  171. Float:mov_speed = SHIP_MOV_SPEED,
  172. timer_step = SHIP_TIMER_STEP)
  173. {
  174. new ship_id = Iter_Free(Ship);
  175. if(ship_id == -1)
  176. return -1;
  177. Iter_Add(Ship, ship_id);
  178. //Main ship (freighter_sfe)
  179. ship_info[ship_id][ship_part][0] = CreateDynamicObject(10230,
  180. x, y, z,
  181. 0.0000000, 0.0000000, rot,
  182. .streamdistance = SHIP_STREAMER_SD,
  183. .drawdistance = SHIP_STREAMER_DD);
  184. ship_info[ship_id][ship_rot_step] = rot_step;
  185. ship_info[ship_id][ship_mov_speed] = mov_speed;
  186. ship_info[ship_id][ship_timer_step] = timer_step;
  187. new
  188. Float:newx, Float:newy, Float:newz,
  189. Float:newrx, Float:newry, Float:newrz
  190. ;
  191. for(new i = 0; i < sizeof(ship_offset); i++)
  192. {
  193. AttachObjectToObjectEx(ship_info[ship_id][ship_part][0],
  194. ship_offset[i][shipX],
  195. ship_offset[i][shipY],
  196. ship_offset[i][shipZ],
  197. 0.0, 0.0, 0.0,
  198. newx, newy, newz,
  199. newrx, newry, newrz,
  200. 0.0);
  201. ship_info[ship_id][ship_part][i+1] = CreateDynamicObject(ship_offset[i][shipModelid],
  202. newx, newy, newz, newrx, newry, newrz,
  203. .worldid = 0,
  204. .interiorid = 0,
  205. .streamdistance = ship_offset[i][shipSD],
  206. .drawdistance = ship_offset[i][shipDD]);
  207. }
  208. #if defined DEBUG_SHIP_INC
  209. printf("CreateShip: created ship %d", ship_id);
  210. #endif
  211. return ship_id;
  212. }
  213. /**--------------------------------------------------------------------------**\
  214. <summary>DestroyShip</summary>
  215. <param name="ship_id">-</param>
  216. <returns>
  217. 0 on fail, 1 otherwise.
  218. </returns>
  219. <remarks>
  220. -
  221. </remarks>
  222. \**--------------------------------------------------------------------------**/
  223. stock DestroyShip(ship_id)
  224. {
  225. if(!Iter_Contains(Ship, ship_id))
  226. return 0;
  227. for(new i = 0; i < sizeof(ship_offset)+1; i++)
  228. {
  229. DestroyDynamicObject(ship_info[ship_id][ship_part][i]);
  230. }
  231. Iter_Remove(Ship, ship_id);
  232. #if defined DEBUG_SHIP_INC
  233. printf("DestroyShip: destroyed ship %d", ship_id);
  234. #endif
  235. return 1;
  236. }
  237. /**--------------------------------------------------------------------------**\
  238. <summary>SetShipBodyMaterial</summary>
  239. <param name="ship_id">-</param>
  240. <param name="objectid">-</param>
  241. <param name="txd">-</param>
  242. <param name="material">-</param>
  243. <param name="color">-</param>
  244. <returns>
  245. 0 on fail, 1 otherwise.
  246. </returns>
  247. <remarks>
  248. -
  249. </remarks>
  250. \**--------------------------------------------------------------------------**/
  251. stock SetShipBodyMaterial(ship_id, objectid, txd[], material[], color = 0xFFFFFFFF)
  252. {
  253. if(!Iter_Contains(Ship, ship_id))
  254. return 0;
  255. //Main parts
  256. SetDynamicObjectMaterial(ship_info[ship_id][ship_part][0], 7, objectid, txd, material, color);
  257. SetDynamicObjectMaterial(ship_info[ship_id][ship_part][0], 9, objectid, txd, material, color);
  258. //Part underwater
  259. SetDynamicObjectMaterial(ship_info[ship_id][ship_part][0], 8, objectid, txd, material, color);
  260. return 1;
  261. }
  262. /**--------------------------------------------------------------------------**\
  263. <summary>SetShipContainerMaterial</summary>
  264. <param name="ship_id">-</param>
  265. <param name="container_type">-</param>
  266. <param name="objectid_body">-</param>
  267. <param name="txd_body">-</param>
  268. <param name="material_body">-</param>
  269. <param name="objectid_doors">-</param>
  270. <param name="txd_doors">-</param>
  271. <param name="material_doors">-</param>
  272. <param name="color">-</param>
  273. <returns>
  274. 0 on fail, 1 otherwise.
  275. </returns>
  276. <remarks>
  277. -
  278. </remarks>
  279. \**--------------------------------------------------------------------------**/
  280. enum
  281. {
  282. CONTAINER_RED = 0,
  283. CONTAINER_BLUE,
  284. CONTAINER_YELLOW
  285. }
  286. stock SetShipContainerMaterial(ship_id, container_type, objectid_body, txd_body[], material_body[],
  287. objectid_doors, txd_doors[], material_doors[], color = 0xFFFFFFFF)
  288. {
  289. if(!Iter_Contains(Ship, ship_id))
  290. return 0;
  291. switch(container_type)
  292. {
  293. case CONTAINER_RED:
  294. {
  295. SetDynamicObjectMaterial(ship_info[ship_id][ship_part][1], 1, objectid_body, txd_body, material_body, color); //Red
  296. SetDynamicObjectMaterial(ship_info[ship_id][ship_part][1], 0, objectid_doors, txd_doors, material_doors, color);
  297. }
  298. case CONTAINER_BLUE:
  299. {
  300. SetDynamicObjectMaterial(ship_info[ship_id][ship_part][1], 2, objectid_body, txd_body, material_body, color); //Blue
  301. SetDynamicObjectMaterial(ship_info[ship_id][ship_part][1], 3, objectid_doors, txd_doors, material_doors, color);
  302. }
  303. case CONTAINER_YELLOW:
  304. {
  305. SetDynamicObjectMaterial(ship_info[ship_id][ship_part][1], 4, objectid_body, txd_body, material_body, color); //Yellow
  306. SetDynamicObjectMaterial(ship_info[ship_id][ship_part][1], 5, objectid_doors, txd_doors, material_doors, color);
  307. }
  308. default:
  309. return 0;
  310. }
  311. return 1;
  312. }
  313. /**--------------------------------------------------------------------------**\
  314. <summary>CreateRoute</summary>
  315. <param name="new_route">-</param>
  316. <param name="size">-</param>
  317. <returns>
  318. -1 on fail, the id of the route otherwise.
  319. </returns>
  320. <remarks>
  321. -
  322. </remarks>
  323. \**--------------------------------------------------------------------------**/
  324. stock CreateRoute(const Float:new_route[][2], size = sizeof(new_route))
  325. {
  326. new route_id = Iter_Free(Route);
  327. if(route_id == -1)
  328. return -1;
  329. Iter_Add(Route, route_id);
  330. size = clamp(size, 0, MAX_ROUTE_POINTS);
  331. for(new i; i < size && i < MAX_ROUTE_POINTS; i++)
  332. {
  333. route_info[route_id][i][0] = new_route[i][0];
  334. route_info[route_id][i][1] = new_route[i][1];
  335. }
  336. route_lenght[route_id] = size;
  337. #if defined DEBUG_SHIP_INC
  338. printf("CreateRoute: created route %d with %d points", route_id, route_lenght[route_id]);
  339. #endif
  340. return route_id;
  341. }
  342. /**--------------------------------------------------------------------------**\
  343. <summary>DestroyRoute</summary>
  344. <param name="route_id">-</param>
  345. <returns>
  346. 0 on fail, 1 otherwise.
  347. </returns>
  348. <remarks>
  349. -
  350. </remarks>
  351. \**--------------------------------------------------------------------------**/
  352. stock DestroyRoute(route_id)
  353. {
  354. if(!Iter_Contains(Route, route_id))
  355. return 0;
  356. Iter_Remove(Route, route_id);
  357. #if defined DEBUG_SHIP_INC
  358. printf("DestroyRoute: destroyed route %d", route_id);
  359. #endif
  360. return 1;
  361. }
  362. /**--------------------------------------------------------------------------**\
  363. <summary>StartRouteForShip</summary>
  364. <param name="route_id">-</param>
  365. <param name="ship_id">-</param>
  366. <returns>
  367. 0 on fail, 1 otherwise.
  368. </returns>
  369. <remarks>
  370. -
  371. </remarks>
  372. \**--------------------------------------------------------------------------**/
  373. stock StartRouteForShip(route_id, ship_id)
  374. {
  375. if(!Iter_Contains(Route, route_id) || !Iter_Contains(Ship, ship_id))
  376. return 0;
  377. if(ship_info[ship_id][ship_route] != -1)
  378. return 0;
  379. ship_info[ship_id][ship_route] = route_id;
  380. ship_route_execute(ship_id, 0);
  381. #if defined DEBUG_SHIP_INC
  382. printf("StartRouteForShip: started route %d for ship %d", route_id, ship_id);
  383. #endif
  384. return 1;
  385. }
  386. /**--------------------------------------------------------------------------**\
  387. <summary>StopRouteForShip</summary>
  388. <param name="ship_id">-</param>
  389. <returns>
  390. 0 on fail, 1 otherwise.
  391. </returns>
  392. <remarks>
  393. -
  394. </remarks>
  395. \**--------------------------------------------------------------------------**/
  396. stock StopRouteForShip(ship_id)
  397. {
  398. if(!Iter_Contains(Ship, ship_id))
  399. return 0;
  400. if(ship_info[ship_id][ship_route] == -1)
  401. return 0;
  402. ship_info[ship_id][ship_route] = -1;
  403. for(new i; i < sizeof(ship_offset)+1; i++)
  404. {
  405. StopDynamicObject(ship_info[ship_id][ship_part][i]);
  406. }
  407. #if defined DEBUG_SHIP_INC
  408. printf("StopRouteForShip: stopped route for ship %d", ship_id);
  409. #endif
  410. return 1;
  411. }
  412. //==============================================================================
  413. /*
  414. * Internal functions start here
  415. */
  416. forward ship_route_execute(ship_id, step);
  417. public ship_route_execute(ship_id, step)
  418. {
  419. if(!Iter_Contains(Ship, ship_id))
  420. return;
  421. new route_id = ship_info[ship_id][ship_route];
  422. if(!Iter_Contains(Route, route_id))
  423. return;
  424. //The route has already been completed
  425. if(step >= route_lenght[route_id] || step >= MAX_ROUTE_POINTS)
  426. {
  427. ship_info[ship_id][ship_route] = -1;
  428. CallLocalFunction("OnShipRouteCompleted", "iii", ship_id, route_id, route_lenght[route_id]);
  429. return;
  430. }
  431. new Float:angle, Float:current;
  432. GetDynamicObjectRot(ship_info[ship_id][ship_part][0], angle, angle, current);
  433. //Get the angle between current and next route points
  434. angle = GetAngleToPoint(route_info[route_id][step][0], route_info[route_id][step][1],
  435. route_info[route_id][step+1][0], route_info[route_id][step+1][1]);
  436. angle -= 90.0;
  437. angle = absoluteangle(angle);
  438. #if defined DEBUG_SHIP_INC
  439. printf("ship_route_execute: rot from %.2f to %.2f", current, angle);
  440. current = absoluteangle(current);
  441. new Float:dest_cur = absoluteangle(angle - current);
  442. new Float:cur_dest = absoluteangle(current - angle);
  443. new Float:rot_step = ship_info[ship_id][ship_rot_step];
  444. if(cur_dest > dest_cur)
  445. {
  446. printf("\tdest_cur %d iters", floatround(dest_cur / rot_step));
  447. printf("\testimated time %d ms", floatround(dest_cur / rot_step * ship_info[ship_id][ship_timer_step]));
  448. }
  449. else
  450. {
  451. printf("\tcur_dest %d iters", floatround(cur_dest / rot_step));
  452. printf("\testimated time %d ms", floatround(cur_dest / rot_step * ship_info[ship_id][ship_timer_step]));
  453. }
  454. #endif
  455. ship_rot(ship_id, current, angle, step, 0);
  456. }
  457. forward ship_rot(ship_id, Float:a, Float:dest, step, status);
  458. public ship_rot(ship_id, Float:a, Float:dest, step, status)
  459. {
  460. if(!Iter_Contains(Ship, ship_id))
  461. return;
  462. static
  463. Float:newx,
  464. Float:newy,
  465. Float:newz,
  466. Float:newrx,
  467. Float:newry,
  468. Float:newrz,
  469. Float:dest_cur,
  470. Float:cur_dest,
  471. route_id
  472. ;
  473. route_id = ship_info[ship_id][ship_route];
  474. if(!Iter_Contains(Route, route_id))
  475. return;
  476. //The route has already been completed
  477. if(step >= route_lenght[route_id]-1)
  478. {
  479. ship_route_execute(ship_id, step+1);
  480. return;
  481. }
  482. a = absoluteangle(a);
  483. dest = absoluteangle(dest);
  484. SetDynamicObjectRot(ship_info[ship_id][ship_part][0], 0.0, 0.0, a);
  485. for(new i = 0; i < sizeof(ship_offset); i++)
  486. {
  487. //Calculate the offsets based on the new rotation
  488. AttachObjectToObjectEx(ship_info[ship_id][ship_part][0],
  489. ship_offset[i][shipX],
  490. ship_offset[i][shipY],
  491. ship_offset[i][shipZ],
  492. 0.0, 0.0, 0.0,
  493. newx, newy, newz,
  494. newrx, newry, newrz,
  495. 0.0);
  496. SetDynamicObjectPos(ship_info[ship_id][ship_part][i+1], newx, newy, newz);
  497. SetDynamicObjectRot(ship_info[ship_id][ship_part][i+1], newrx, newry, newrz);
  498. }
  499. a = absoluteangle(a);
  500. dest = absoluteangle(dest);
  501. if (!status)
  502. {
  503. dest_cur = absoluteangle(dest - a),
  504. cur_dest = absoluteangle(a - dest);
  505. if(cur_dest > dest_cur)
  506. {
  507. a += ship_info[ship_id][ship_rot_step];
  508. }
  509. else
  510. {
  511. a -= ship_info[ship_id][ship_rot_step];
  512. }
  513. #if defined DEBUG_SHIP_INC
  514. //SetPlayerMapIcon(0, 0, newx, newy, newz, 9, -1, MAPICON_GLOBAL);
  515. //SetPlayerRaceCheckpoint(0, 0, newx, newy, newz, 0.0, 0.0, 0.0, 5.0);
  516. /*
  517. printf("\t\t%.4f <= %.4f && %.4f >= %.4f = %d",
  518. a, dest+0.5, a, dest-0.5,
  519. _:(a <= dest+0.5 && a >= dest-0.5));
  520. */
  521. #endif
  522. if(a <= dest+0.5 && a >= dest-0.5)
  523. {
  524. a = dest;
  525. status = 1;
  526. }
  527. SetTimerEx("ship_rot", ship_info[ship_id][ship_timer_step], false,
  528. "iffii", ship_id, a, dest, step, status);
  529. }
  530. else
  531. {
  532. //The rotation has been completed, now move the ship to the next point
  533. new completion;
  534. new Float:x, Float:y, Float:z;
  535. new Float:dist = GetDistanceBetweenPoints_Ships(route_info[route_id][step][0], route_info[route_id][step][1], 0.0,
  536. route_info[route_id][step+1][0], route_info[route_id][step+1][1], 0.0);
  537. dest += 90.0;
  538. for(new i; i < sizeof(ship_offset)+1; i++)
  539. {
  540. GetDynamicObjectPos(ship_info[ship_id][ship_part][i], x, y, z);
  541. GetXYInDirection(x, y, dest, dist);
  542. completion = MoveDynamicObject(ship_info[ship_id][ship_part][i],
  543. x, y, z,
  544. ship_info[ship_id][ship_mov_speed]);
  545. }
  546. #if defined DEBUG_SHIP_INC
  547. printf("\tMoving from %.4f, %.4f to %.4f, %.4f (%.2f meters) in %d ms (step = %d)",
  548. route_info[route_id][step][0], route_info[route_id][step][1],
  549. route_info[route_id][step+1][0], route_info[route_id][step+1][1],
  550. dist, completion,
  551. step);
  552. #endif
  553. //Once the movement has been completed, get to the next step
  554. SetTimerEx("ship_route_execute", completion, 0, "ii", ship_id, step+1);
  555. }
  556. }
  557. //==============================================================================
  558. static GetXYInDirection(& Float: X, & Float: Y, Float: Angle, Float: distance = 1.0)
  559. {
  560. X -= (floatsin(Angle, degrees) * distance);
  561. Y += (floatcos(Angle, degrees) * distance);
  562. }
  563. /*
  564. Thanks to adri1 & Pottus for the following function(s):
  565. http://forum.sa-mp.com/showpost.php?p=3144750&postcount=4
  566. */
  567. static AttachObjectToObjectEx(attachoid, Float:off_x, Float:off_y, Float:off_z, Float:rot_x, Float:rot_y, Float:rot_z, &Float:X, &Float:Y, &Float:Z, &Float:RX, &Float:RY, &Float:RZ, Float:erroroff = 0.0) // By Stylock - [url]http://forum.sa-mp.com/member.php?u=114165[/url]
  568. {
  569. static
  570. Float:sin[3],
  571. Float:cos[3],
  572. Float:pos[3],
  573. Float:rot[3];
  574. GetDynamicObjectPos(attachoid, pos[0], pos[1], pos[2]);
  575. GetDynamicObjectRot(attachoid, rot[0], rot[1], rot[2]);
  576. rot[2] += erroroff;
  577. EDIT_FloatEulerFix(rot[0], rot[1], rot[2]);
  578. cos[0] = floatcos(rot[0], degrees); cos[1] = floatcos(rot[1], degrees); cos[2] = floatcos(rot[2], degrees); sin[0] = floatsin(rot[0], degrees); sin[1] = floatsin(rot[1], degrees); sin[2] = floatsin(rot[2], degrees);
  579. pos[0] = pos[0] + off_x * cos[1] * cos[2] - off_x * sin[0] * sin[1] * sin[2] - off_y * cos[0] * sin[2] + off_z * sin[1] * cos[2] + off_z * sin[0] * cos[1] * sin[2];
  580. pos[1] = pos[1] + off_x * cos[1] * sin[2] + off_x * sin[0] * sin[1] * cos[2] + off_y * cos[0] * cos[2] + off_z * sin[1] * sin[2] - off_z * sin[0] * cos[1] * cos[2];
  581. pos[2] = pos[2] - off_x * cos[0] * sin[1] + off_y * sin[0] + off_z * cos[0] * cos[1];
  582. rot[0] = asin(cos[0] * cos[1]); rot[1] = atan2(sin[0], cos[0] * sin[1]) + rot_z; rot[2] = atan2(cos[1] * cos[2] * sin[0] - sin[1] * sin[2], cos[2] * sin[1] - cos[1] * sin[0] * -sin[2]);
  583. cos[0] = floatcos(rot[0], degrees); cos[1] = floatcos(rot[1], degrees); cos[2] = floatcos(rot[2], degrees); sin[0] = floatsin(rot[0], degrees); sin[1] = floatsin(rot[1], degrees); sin[2] = floatsin(rot[2], degrees);
  584. rot[0] = asin(cos[0] * sin[1]); rot[1] = atan2(cos[0] * cos[1], sin[0]); rot[2] = atan2(cos[2] * sin[0] * sin[1] - cos[1] * sin[2], cos[1] * cos[2] + sin[0] * sin[1] * sin[2]);
  585. cos[0] = floatcos(rot[0], degrees); cos[1] = floatcos(rot[1], degrees); cos[2] = floatcos(rot[2], degrees); sin[0] = floatsin(rot[0], degrees); sin[1] = floatsin(rot[1], degrees); sin[2] = floatsin(rot[2], degrees);
  586. rot[0] = atan2(sin[0], cos[0] * cos[1]) + rot_x; rot[1] = asin(cos[0] * sin[1]); rot[2] = atan2(cos[2] * sin[0] * sin[1] + cos[1] * sin[2], cos[1] * cos[2] - sin[0] * sin[1] * sin[2]);
  587. cos[0] = floatcos(rot[0], degrees); cos[1] = floatcos(rot[1], degrees); cos[2] = floatcos(rot[2], degrees); sin[0] = floatsin(rot[0], degrees); sin[1] = floatsin(rot[1], degrees); sin[2] = floatsin(rot[2], degrees);
  588. rot[0] = asin(cos[1] * sin[0]); rot[1] = atan2(sin[1], cos[0] * cos[1]) + rot_y; rot[2] = atan2(cos[0] * sin[2] - cos[2] * sin[0] * sin[1], cos[0] * cos[2] + sin[0] * sin[1] * sin[2]);
  589. X = pos[0];
  590. Y = pos[1];
  591. Z = pos[2];
  592. RX = rot[0];
  593. RY = rot[1];
  594. RZ = rot[2];
  595. }
  596. static EDIT_FloatEulerFix(&Float:rot_x, &Float:rot_y, &Float:rot_z)
  597. {
  598. EDIT_FloatGetRemainder(rot_x, rot_y, rot_z);
  599. if((!floatcmp(rot_x, 0.0) || !floatcmp(rot_x, 360.0))
  600. && (!floatcmp(rot_y, 0.0) || !floatcmp(rot_y, 360.0)))
  601. {
  602. rot_y = 0.0000002;
  603. }
  604. return 1;
  605. }
  606. static EDIT_FloatGetRemainder(&Float:rot_x, &Float:rot_y, &Float:rot_z)
  607. {
  608. EDIT_FloatRemainder(rot_x, 360.0);
  609. EDIT_FloatRemainder(rot_y, 360.0);
  610. EDIT_FloatRemainder(rot_z, 360.0);
  611. return 1;
  612. }
  613. static EDIT_FloatRemainder(&Float:remainder, Float:value)
  614. {
  615. if(remainder >= value)
  616. {
  617. while(remainder >= value)
  618. {
  619. remainder = remainder - value;
  620. }
  621. }
  622. else if(remainder < 0.0)
  623. {
  624. while(remainder < 0.0)
  625. {
  626. remainder = remainder + value;
  627. }
  628. }
  629. return 1;
  630. }