bodyguards.pwn 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. /* ---------------------------------
  2. FCNPC Plugin bodyguards FS
  3. - File: bodyguards.pwn
  4. - Author: ziggi
  5. ---------------------------------*/
  6. #define FILTERSCRIPT
  7. #include <a_samp>
  8. #if !defined _FCNPC_included
  9. #tryinclude <FCNPC>
  10. #endif
  11. #if !defined _FCNPC_included
  12. #tryinclude "FCNPC"
  13. #endif
  14. #if !defined _FCNPC_included
  15. #tryinclude "../FCNPC"
  16. #endif
  17. #if !defined _FCNPC_included
  18. #error Add FCNPC.inc to your scripts directory
  19. #endif
  20. /*
  21. Defines
  22. */
  23. #define MAX_BODYGUARDS 6
  24. #define DEBUG
  25. #define MAX_BODYPART_NAME 10
  26. #define BG_INVALID_SLOT_ID -1
  27. /*
  28. Vars
  29. */
  30. static
  31. gPlayerNpc[MAX_PLAYERS][MAX_BODYGUARDS],
  32. gNpcSlot[MAX_PLAYERS],
  33. gNpcPlayer[MAX_PLAYERS],
  34. gFollowTimer[MAX_PLAYERS],
  35. gFollowTarget[MAX_PLAYERS],
  36. PlayerText3D:gNpcText3D[MAX_PLAYERS];
  37. /*
  38. Publics
  39. */
  40. public OnFilterScriptInit()
  41. {
  42. for (new playerid; playerid < MAX_PLAYERS; playerid++) {
  43. for (new slot; slot < MAX_BODYGUARDS; slot++) {
  44. gPlayerNpc[playerid][slot] = INVALID_PLAYER_ID;
  45. }
  46. gNpcSlot[playerid] = BG_INVALID_SLOT_ID;
  47. gNpcPlayer[playerid] = INVALID_PLAYER_ID;
  48. gFollowTimer[playerid] = 0;
  49. gFollowTarget[playerid] = INVALID_PLAYER_ID;
  50. }
  51. printf("\n-------------------------------");
  52. printf(" FCNPC Bodyguard System");
  53. printf(" Author: ziggi");
  54. printf("-------------------------------\n");
  55. return 1;
  56. }
  57. public OnFilterScriptExit()
  58. {
  59. for (new playerid; playerid < MAX_PLAYERS; playerid++) {
  60. if (BG_IsValid(playerid)) {
  61. BG_DeleteByID(playerid);
  62. }
  63. }
  64. }
  65. public OnPlayerDisconnect(playerid, reason)
  66. {
  67. if (!BG_IsValid(playerid)) {
  68. for (new slot; slot < MAX_BODYGUARDS; slot++) {
  69. if (BG_IsValidSlot(playerid, slot)) {
  70. BG_Delete(playerid, slot);
  71. }
  72. }
  73. }
  74. return 1;
  75. }
  76. public FCNPC_OnReachDestination(npcid)
  77. {
  78. BG_SetFollowTimer(npcid);
  79. }
  80. public FCNPC_OnTakeDamage(npcid, issuerid, Float:amount, weaponid, bodypart)
  81. {
  82. if (!IsPlayerConnected(issuerid) || !BG_IsValid(npcid)) {
  83. return 1;
  84. }
  85. #if defined DEBUG
  86. new
  87. string[44 + 3 + MAX_PLAYER_NAME + 3 + 2 + MAX_BODYPART_NAME + 16],
  88. player_name[MAX_PLAYER_NAME + 1],
  89. bodypart_name[MAX_BODYPART_NAME],
  90. weapon_name[16];
  91. GetPlayerName(issuerid, player_name, sizeof(player_name));
  92. GetBodypartName(bodypart, bodypart_name);
  93. GetWeaponName(weaponid, weapon_name, sizeof(weapon_name));
  94. format(string, sizeof(string),
  95. "NPC(%d) was damaged by %s(%d) with %s(%d) in the %s (hp: %f)",
  96. npcid, player_name, issuerid, weapon_name, weaponid, bodypart_name, amount);
  97. SendClientMessageToAll(0xFF0000FF, string);
  98. #endif
  99. return 1;
  100. }
  101. public FCNPC_OnVehicleEntryComplete(npcid, vehicleid, seatid)
  102. {
  103. #if defined DEBUG
  104. new string[27 + 3 + 1];
  105. format(string, sizeof(string), "NPC %d finished vehicle entry", npcid);
  106. SendClientMessageToAll(0xFF0000FF, string);
  107. #endif
  108. return 1;
  109. }
  110. public FCNPC_OnVehicleExitComplete(npcid, vehicleid)
  111. {
  112. #if defined DEBUG
  113. new string[26 + 3 + 1];
  114. format(string, sizeof(string), "NPC %d finished vehicle exit", npcid);
  115. SendClientMessageToAll(0xFF0000FF, string);
  116. #endif
  117. return 1;
  118. }
  119. public OnPlayerCommandText(playerid, cmdtext[])
  120. {
  121. new
  122. cmd[20],
  123. subcmd[20],
  124. param[20],
  125. idx;
  126. cmd = strcharsplit(cmdtext, idx);
  127. if (!strcmp(cmd, "/bg", true)) {
  128. subcmd = strcharsplit(cmdtext, idx);
  129. if (strlen(subcmd) == 0) {
  130. SendClientMessage(playerid, -1, "{8470FF}Use: {FFFFFF}/bg [option]");
  131. SendClientMessage(playerid, -1, "{8470FF}Options: {FFFFFF}add, delete, follow, unfollow, enter, exit");
  132. SendClientMessage(playerid, -1, "{8470FF}Options: {FFFFFF}shoot, aim, reset");
  133. return 1;
  134. }
  135. if (!strcmp(subcmd, "add", true)) {
  136. new npcid = BG_Add(playerid);
  137. if (npcid < 0) {
  138. if (npcid == -1) {
  139. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Maximum bodyguards allowed per player is reached.");
  140. } else if (npcid == -2) {
  141. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}No slots available.");
  142. } else {
  143. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Unknown error.");
  144. }
  145. return 1;
  146. }
  147. new
  148. Float:player_x,
  149. Float:player_y,
  150. Float:player_z,
  151. Float:player_angle;
  152. GetPlayerPos(playerid, player_x, player_y, player_z);
  153. GetPlayerFacingAngle(playerid, player_angle);
  154. new
  155. Float:pos_x,
  156. Float:pos_y;
  157. GetCoordsInFront(player_x, player_y, player_angle, 2.0, pos_x, pos_y);
  158. FCNPC_Spawn(npcid, random(4) + 163, pos_x, pos_y, player_z);
  159. FCNPC_SetAngleToPlayer(npcid, playerid);
  160. FCNPC_SetVirtualWorld(npcid, GetPlayerVirtualWorld(playerid));
  161. FCNPC_SetInterior(npcid, GetPlayerInterior(playerid));
  162. FCNPC_SetWeapon(npcid, random(3) + 22);
  163. FCNPC_UseInfiniteAmmo(npcid, true);
  164. FCNPC_SetArmour(npcid, 80);
  165. FCNPC_SetFightingStyle(npcid, random(4) + 3);
  166. new label_text[2 + 3 + 1];
  167. format(label_text, sizeof(label_text), "[%d]", BG_GetSlotByID(npcid));
  168. gNpcText3D[npcid] = CreatePlayer3DTextLabel(playerid, label_text, 0xFFFFFFFF, 0.0, 0.0, 0.0, 5.0, npcid);
  169. #if defined DEBUG
  170. new
  171. string[38 + MAX_PLAYER_NAME + 3 + 1],
  172. playername[MAX_PLAYER_NAME + 1];
  173. GetPlayerName(playerid, playername, sizeof(playername));
  174. format(string, sizeof(string), "Player %s (ID: %d) has created a bodyguard", playername, playerid);
  175. SendClientMessageToAll(0xFF0000FF, string);
  176. #endif
  177. return 1;
  178. }
  179. if (!strcmp(subcmd, "delete", true)) {
  180. param = strcharsplit(cmdtext, idx);
  181. if (strlen(param) == 0) {
  182. SendClientMessage(playerid, -1, "{8470FF}Use: {FFFFFF}/bg delete [slot]");
  183. return 1;
  184. }
  185. new slot = strval(param);
  186. if (!BG_IsValidSlot(playerid, slot)) {
  187. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Invalid bodyguard.");
  188. return 1;
  189. }
  190. BG_Delete(playerid, slot);
  191. return 1;
  192. }
  193. if (!strcmp(subcmd, "follow", true)) {
  194. param = strcharsplit(cmdtext, idx);
  195. if (strlen(param) == 0) {
  196. SendClientMessage(playerid, -1, "{8470FF}Use: {FFFFFF}/bg follow [slot]");
  197. return 1;
  198. }
  199. new slot = strval(param);
  200. if (!BG_IsValidSlot(playerid, slot)) {
  201. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Invalid bodyguard.");
  202. return 1;
  203. }
  204. BG_FollowPlayer(playerid, slot, playerid);
  205. return 1;
  206. }
  207. if (!strcmp(subcmd, "unfollow", true)) {
  208. param = strcharsplit(cmdtext, idx);
  209. if (strlen(param) == 0) {
  210. SendClientMessage(playerid, -1, "{8470FF}Use: {FFFFFF}/bg unfollow [slot]");
  211. return 1;
  212. }
  213. new slot = strval(param);
  214. if (!BG_IsValidSlot(playerid, slot)) {
  215. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Invalid bodyguard.");
  216. return 1;
  217. }
  218. BG_UnFollowPlayer(playerid, slot);
  219. return 1;
  220. }
  221. if (!strcmp(subcmd, "aim", true)) {
  222. param = strcharsplit(cmdtext, idx);
  223. if (strlen(param) == 0) {
  224. SendClientMessage(playerid, -1, "{8470FF}Use: {FFFFFF}/bg aim [slot] [targetid]");
  225. return 1;
  226. }
  227. new slot = strval(param);
  228. if (!BG_IsValidSlot(playerid, slot)) {
  229. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Invalid bodyguard.");
  230. return 1;
  231. }
  232. param = strcharsplit(cmdtext, idx);
  233. if (strlen(param) == 0) {
  234. SendClientMessage(playerid, -1, "{8470FF}Use: {FFFFFF}/bg aim [slot] [targetid]");
  235. return 1;
  236. }
  237. new targetid = strval(param);
  238. if (!IsPlayerConnected(targetid)) {
  239. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Invalid target.");
  240. return 1;
  241. }
  242. BG_Aim(playerid, slot, targetid);
  243. return 1;
  244. }
  245. if (!strcmp(subcmd, "shoot", true)) {
  246. param = strcharsplit(cmdtext, idx);
  247. if (strlen(param) == 0) {
  248. SendClientMessage(playerid, -1, "{8470FF}Use: {FFFFFF}/bg shoot [slot] [targetid]");
  249. return 1;
  250. }
  251. new slot = strval(param);
  252. if (!BG_IsValidSlot(playerid, slot)) {
  253. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Invalid bodyguard.");
  254. return 1;
  255. }
  256. param = strcharsplit(cmdtext, idx);
  257. if (strlen(param) == 0) {
  258. SendClientMessage(playerid, -1, "{8470FF}Use: {FFFFFF}/bg shoot [slot] [targetid]");
  259. return 1;
  260. }
  261. new targetid = strval(param);
  262. if (!IsPlayerConnected(targetid)) {
  263. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Invalid target.");
  264. return 1;
  265. }
  266. BG_Shoot(playerid, slot, targetid);
  267. return 1;
  268. }
  269. if (!strcmp(subcmd, "reset", true)) {
  270. param = strcharsplit(cmdtext, idx);
  271. if (strlen(param) == 0) {
  272. SendClientMessage(playerid, -1, "{8470FF}Use: {FFFFFF}/bg reset [slot]");
  273. return 1;
  274. }
  275. new slot = strval(param);
  276. if (!BG_IsValidSlot(playerid, slot)) {
  277. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Invalid bodyguard.");
  278. return 1;
  279. }
  280. BG_AimReset(playerid, slot);
  281. return 1;
  282. }
  283. if (!strcmp(subcmd, "enter", true)) {
  284. param = strcharsplit(cmdtext, idx);
  285. if (strlen(param) == 0) {
  286. SendClientMessage(playerid, -1, "{8470FF}Use: {FFFFFF}/bg enter [slot] [vehicleid] [seat]");
  287. return 1;
  288. }
  289. new slot = strval(param);
  290. if (!BG_IsValidSlot(playerid, slot)) {
  291. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Invalid bodyguard.");
  292. return 1;
  293. }
  294. param = strcharsplit(cmdtext, idx);
  295. if (strlen(param) == 0) {
  296. SendClientMessage(playerid, -1, "{8470FF}Use: {FFFFFF}/bg enter [slot] [vehicleid] [seat]");
  297. return 1;
  298. }
  299. new vehicleid = strval(param);
  300. if (!GetVehicleModel(vehicleid)) {
  301. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Invalid target.");
  302. return 1;
  303. }
  304. param = strcharsplit(cmdtext, idx);
  305. new seat = strval(param);
  306. BG_UnFollowPlayer(playerid, slot);
  307. BG_EnterVehicle(playerid, slot, vehicleid, seat);
  308. return 1;
  309. }
  310. if (!strcmp(subcmd, "exit", true)) {
  311. param = strcharsplit(cmdtext, idx);
  312. if (strlen(param) == 0) {
  313. SendClientMessage(playerid, -1, "{8470FF}Use: {FFFFFF}/bg exit [slot]");
  314. return 1;
  315. }
  316. new slot = strval(param);
  317. if (!BG_IsValidSlot(playerid, slot)) {
  318. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Invalid bodyguard.");
  319. return 1;
  320. }
  321. BG_ExitVehicle(playerid, slot);
  322. return 1;
  323. }
  324. if (!strcmp(subcmd, "melee", true)) {
  325. param = strcharsplit(cmdtext, idx);
  326. if (strlen(param) == 0) {
  327. SendClientMessage(playerid, -1, "{8470FF}Use: {FFFFFF}/bg melee [slot]");
  328. return 1;
  329. }
  330. new slot = strval(param);
  331. if (!BG_IsValidSlot(playerid, slot)) {
  332. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Invalid bodyguard.");
  333. return 1;
  334. }
  335. BG_Melee(playerid, slot);
  336. return 1;
  337. }
  338. if (!strcmp(subcmd, "stopmelee", true)) {
  339. param = strcharsplit(cmdtext, idx);
  340. if (strlen(param) == 0) {
  341. SendClientMessage(playerid, -1, "{8470FF}Use: {FFFFFF}/bg stopmelee [slot]");
  342. return 1;
  343. }
  344. new slot = strval(param);
  345. if (!BG_IsValidSlot(playerid, slot)) {
  346. SendClientMessage(playerid, -1, "{CC0000}Error: {FFFFFF}Invalid bodyguard.");
  347. return 1;
  348. }
  349. BG_MeleeStop(playerid, slot);
  350. return 1;
  351. }
  352. }
  353. return 0;
  354. }
  355. /*
  356. Vehicle functions
  357. */
  358. stock BG_EnterVehicle(playerid, slot, vehicleid, seat)
  359. {
  360. new npcid = gPlayerNpc[playerid][slot];
  361. FCNPC_EnterVehicle(npcid, vehicleid, seat, FCNPC_MOVE_TYPE_RUN);
  362. }
  363. stock BG_ExitVehicle(playerid, slot)
  364. {
  365. new npcid = gPlayerNpc[playerid][slot];
  366. FCNPC_ExitVehicle(npcid);
  367. }
  368. /*
  369. Aim functions
  370. */
  371. stock BG_Aim(playerid, slot, targetid)
  372. {
  373. new npcid = gPlayerNpc[playerid][slot];
  374. FCNPC_AimAtPlayer(npcid, targetid);
  375. }
  376. stock BG_Shoot(playerid, slot, targetid)
  377. {
  378. new npcid = gPlayerNpc[playerid][slot];
  379. FCNPC_AimAtPlayer(npcid, targetid, .shoot = true);
  380. }
  381. stock BG_AimReset(playerid, slot)
  382. {
  383. new npcid = gPlayerNpc[playerid][slot];
  384. FCNPC_StopAim(npcid);
  385. }
  386. /*
  387. Melee functions
  388. */
  389. stock BG_Melee(playerid, slot)
  390. {
  391. BG_MeleeStop(playerid, slot);
  392. new npcid = gPlayerNpc[playerid][slot];
  393. SetPVarInt(npcid, "bg_last_weapon", FCNPC_GetWeapon(npcid));
  394. FCNPC_SetWeapon(npcid, 0);
  395. FCNPC_MeleeAttack(npcid, .fighting_style = true);
  396. }
  397. stock BG_MeleeStop(playerid, slot)
  398. {
  399. new npcid = gPlayerNpc[playerid][slot];
  400. FCNPC_SetWeapon(npcid, GetPVarInt(npcid, "bg_last_weapon"));
  401. FCNPC_StopAttack(npcid);
  402. }
  403. /*
  404. Follow functions
  405. */
  406. stock BG_SetFollowTimer(npcid)
  407. {
  408. if (gFollowTarget[npcid] != INVALID_PLAYER_ID) {
  409. gFollowTimer[npcid] = SetTimerEx("BG_SetFollowPosition", 300, true, "ii", npcid, gFollowTarget[npcid]);
  410. }
  411. }
  412. stock BG_FollowPlayer(playerid, slot, targetid)
  413. {
  414. BG_UnFollowPlayer(playerid, slot);
  415. new npcid = gPlayerNpc[playerid][slot];
  416. gFollowTarget[npcid] = targetid;
  417. new isgo = BG_SetFollowPosition(npcid, targetid);
  418. if (!isgo) {
  419. BG_SetFollowTimer(npcid);
  420. }
  421. }
  422. stock BG_UnFollowPlayer(playerid, slot)
  423. {
  424. new npcid = gPlayerNpc[playerid][slot];
  425. if (gFollowTimer[npcid] != 0) {
  426. KillTimer(gFollowTimer[npcid]);
  427. gFollowTimer[npcid] = 0;
  428. }
  429. if (gFollowTarget[npcid] == INVALID_PLAYER_ID) {
  430. return 0;
  431. }
  432. gFollowTarget[npcid] = INVALID_PLAYER_ID;
  433. return 1;
  434. }
  435. forward BG_SetFollowPosition(npcid, playerid);
  436. public BG_SetFollowPosition(npcid, playerid)
  437. {
  438. new
  439. Float:pos_x,
  440. Float:pos_y,
  441. Float:pos_z,
  442. Float:min_distance,
  443. Float:range,
  444. Float:speed;
  445. GetPlayerPos(playerid, pos_x, pos_y, pos_z);
  446. if (FCNPC_GetVehicleID(npcid) != INVALID_VEHICLE_ID) {
  447. min_distance = -3.0;
  448. range = -min_distance + 1.0;
  449. speed = 0.8;
  450. } else {
  451. min_distance = -1.0;
  452. range = -min_distance + 0.5;
  453. speed = FCNPC_MOVE_SPEED_AUTO;
  454. }
  455. if (!IsPlayerInRangeOfPoint(npcid, range, pos_x, pos_y, pos_z)) {
  456. FCNPC_GoToPlayer(npcid, playerid, .speed = speed, .min_distance = min_distance);
  457. KillTimer(gFollowTimer[npcid]);
  458. gFollowTimer[npcid] = 0;
  459. return 1;
  460. }
  461. return 0;
  462. }
  463. /*
  464. Add/Delete functions
  465. */
  466. stock BG_Add(playerid)
  467. {
  468. new slot = BG_GetFreeSlot(playerid);
  469. if (slot == BG_INVALID_SLOT_ID) {
  470. return -1;
  471. }
  472. new name[MAX_PLAYER_NAME + 1];
  473. format(name, sizeof(name), "Guard_%d_%d", playerid, slot);
  474. new npcid = FCNPC_Create(name);
  475. if (npcid == INVALID_PLAYER_ID) {
  476. return -2;
  477. }
  478. gPlayerNpc[playerid][slot] = npcid;
  479. gNpcPlayer[npcid] = playerid;
  480. gNpcSlot[npcid] = slot;
  481. return npcid;
  482. }
  483. stock BG_Delete(playerid, slot)
  484. {
  485. new npcid = gPlayerNpc[playerid][slot];
  486. FCNPC_Destroy(npcid);
  487. BG_UnFollowPlayer(playerid, slot);
  488. DeletePlayer3DTextLabel(playerid, gNpcText3D[npcid]);
  489. gPlayerNpc[playerid][slot] = INVALID_PLAYER_ID;
  490. gNpcPlayer[npcid] = INVALID_PLAYER_ID;
  491. gNpcSlot[npcid] = BG_INVALID_SLOT_ID;
  492. }
  493. stock BG_DeleteByID(npcid)
  494. {
  495. new playerid = gNpcPlayer[npcid];
  496. new slot = gNpcSlot[npcid];
  497. BG_Delete(playerid, slot);
  498. }
  499. /*
  500. Slot functions
  501. */
  502. stock BG_IsValidSlot(playerid, slot)
  503. {
  504. if (slot < 0 || slot > sizeof(gPlayerNpc[])) {
  505. return false;
  506. }
  507. return gPlayerNpc[playerid][slot] != INVALID_PLAYER_ID;
  508. }
  509. stock BG_IsValid(npcid)
  510. {
  511. return FCNPC_IsValid(npcid) && gNpcSlot[npcid] != BG_INVALID_SLOT_ID;
  512. }
  513. stock BG_GetFreeSlot(playerid)
  514. {
  515. for (new slot; slot < sizeof(gPlayerNpc[]); slot++) {
  516. if (gPlayerNpc[playerid][slot] == INVALID_PLAYER_ID) {
  517. return slot;
  518. }
  519. }
  520. return BG_INVALID_SLOT_ID;
  521. }
  522. stock BG_GetSlotByID(npcid)
  523. {
  524. return gNpcSlot[npcid];
  525. }
  526. /*
  527. Other functions
  528. */
  529. stock strcharsplit(const string[], &index, seperator = ' ')
  530. {
  531. new
  532. result[20],
  533. i;
  534. if (index != 0 && string[index] != '\0') {
  535. index++;
  536. }
  537. while (string[index] && string[index] != seperator && string[index] != '\r' && string[index] != '\n') {
  538. result[i++] = string[index++];
  539. }
  540. return result;
  541. }
  542. stock GetCoordsInFront(Float:x, Float:y, Float:a, Float:distance, &Float:res_x, &Float:res_y)
  543. {
  544. res_x = x + (distance * floatsin(-a, degrees));
  545. res_y = y + (distance * floatcos(-a, degrees));
  546. }
  547. stock GetBodypartName(bodypart, name[], const size = sizeof(name))
  548. {
  549. static const
  550. names[][] = {
  551. !"torso",
  552. !"groin",
  553. !"left arm",
  554. !"right arm",
  555. !"left leg",
  556. !"right leg",
  557. !"head"
  558. };
  559. if (9 < bodypart < 3) {
  560. return 0;
  561. }
  562. return strunpack(name, names[bodypart - 3], size);
  563. }