bg.pwn 15 KB

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