Advertisement
Guest User

for-eldad

a guest
Aug 27th, 2015
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.13 KB | None | 0 0
  1. #include <amxmodx>
  2. #include <amxmisc>
  3. #include <fakemeta>
  4. #include <engine>
  5. #include <hamsandwich>
  6.  
  7.  
  8. //Boolean of when NPC spawned
  9. new bool: g_NpcSpawn[256];
  10. //Boolean to check if NPC is alive or not
  11. new bool: g_NpcDead[256];
  12. //Classname for our NPC
  13. new const g_NpcClassName[] = "ent_npc";
  14. //Constant model for NPC
  15. new const g_NpcModel[] = "models/clown.mdl";
  16.  
  17. //List of sounds our NPC will emit when damaged
  18. new const g_NpcSoundPain[][] =
  19. {
  20. "barney/ba_pain1.wav",
  21. "barney/ba_pain2.wav",
  22. "barney/ba_pain3.wav"
  23. }
  24.  
  25. //Sounds when killed
  26. new const g_NpcSoundDeath[][] =
  27. {
  28. "barney/ba_die1.wav",
  29. "barney/ba_die2.wav",
  30. "barney/ba_die3.wav"
  31. }
  32.  
  33. //Sounds when we knife our flesh NPC
  34. new const g_NpcSoundKnifeHit[][] =
  35. {
  36. "weapons/knife_hit1.wav",
  37. "weapons/knife_hit2.wav",
  38. "weapons/knife_hit3.wav",
  39. "weapons/knife_hit4.wav"
  40. }
  41.  
  42. new const g_NpcSoundKnifeStab[] = "weapons/knife_stab.wav";
  43.  
  44. //List of idle animations
  45. new const NPC_IdleAnimations[] = { 0, 1, 2, 3, 11, 12, 18, 21, 39, 63, 65 };
  46.  
  47. //Sprites for blood when our NPC is damaged
  48. new spr_blood_drop, spr_blood_spray
  49.  
  50. //Player cooldown for using our NPC
  51. new Float: g_Cooldown[32];
  52.  
  53. //Boolean to check if we knifed our NPC
  54. new bool: g_Hit[32];
  55.  
  56. public plugin_init()
  57. {
  58. register_plugin("NPC Plugin", "1.1", "AMXX");
  59.  
  60. register_clcmd("say /npc", "ClCmd_NPC");
  61.  
  62. register_event("HLTV", "Event_NewRound", "a", "1=0", "2=0");
  63.  
  64. RegisterHam(Ham_TakeDamage, "info_target", "npc_TakeDamage");
  65. RegisterHam(Ham_Killed, "info_target", "npc_Killed");
  66. RegisterHam(Ham_Think, "info_target", "npc_Think");
  67. RegisterHam(Ham_TraceAttack, "info_target", "npc_TraceAttack");
  68. RegisterHam(Ham_ObjectCaps, "player", "npc_ObjectCaps", 1 );
  69.  
  70. register_forward(FM_EmitSound, "npc_EmitSound");
  71. }
  72.  
  73. public plugin_precache()
  74. {
  75. spr_blood_drop = precache_model("sprites/blood.spr")
  76. spr_blood_spray = precache_model("sprites/bloodspray.spr")
  77.  
  78. new i;
  79. for(i = 0 ; i < sizeof g_NpcSoundPain ; i++)
  80. precache_sound(g_NpcSoundPain[i]);
  81. for(i = 0 ; i < sizeof g_NpcSoundDeath ; i++)
  82. precache_sound(g_NpcSoundDeath[i]);
  83.  
  84. precache_model(g_NpcModel)
  85. }
  86.  
  87. public plugin_cfg()
  88. {
  89. Load_Npc()
  90. }
  91.  
  92. public ClCmd_NPC(id)
  93. {
  94. //Create a new menu
  95. new menu = menu_create("NPC: Main Menu", "Menu_Handler");
  96.  
  97. //Add some items to the newly created menu
  98. menu_additem(menu, "Create NPC", "1");
  99. menu_additem(menu, "Delete NPC", "2");
  100. menu_additem(menu, "Save current NPC locations", "3");
  101. menu_additem(menu, "Delete all NPC", "4");
  102.  
  103. //Let the menu have an 'Exit' option
  104. menu_setprop(menu, MPROP_EXIT, MEXIT_ALL);
  105.  
  106. //Display our menu
  107. menu_display(id, menu);
  108. }
  109.  
  110. public Menu_Handler(id, menu, item)
  111. {
  112. //If user chose to exit menu we will destroy our menu
  113. if(item == MENU_EXIT)
  114. {
  115. menu_destroy(menu);
  116. return PLUGIN_HANDLED;
  117. }
  118.  
  119. new info[6], szName[64];
  120. new access, callback;
  121.  
  122. menu_item_getinfo(menu, item, access, info, charsmax(info), szName, charsmax(szName), callback);
  123.  
  124. new key = str_to_num(info);
  125.  
  126. switch(key)
  127. {
  128. case 1:
  129. {
  130. //Create our NPC
  131. Create_Npc(id);
  132. }
  133. case 2:
  134. {
  135. //Remove our NPC by the users aim
  136. new iEnt, body, szClassname[32];
  137. get_user_aiming(id, iEnt, body);
  138.  
  139. if (is_valid_ent(iEnt))
  140. {
  141. entity_get_string(iEnt, EV_SZ_classname, szClassname, charsmax(szClassname));
  142.  
  143. if (equal(szClassname, g_NpcClassName))
  144. {
  145. remove_entity(iEnt);
  146. }
  147.  
  148. }
  149. }
  150. case 3:
  151. {
  152. //Save the current locations of all the NPCs
  153. Save_Npc();
  154.  
  155. client_print(id, print_chat, "[AMXX] NPC origin saved succesfully");
  156. }
  157. case 4:
  158. {
  159. //Remove all NPCs from the map
  160. remove_entity_name(g_NpcClassName);
  161.  
  162. client_print(id, print_chat, "[AMXX] ALL NPC origin removed");
  163. }
  164. }
  165.  
  166. //Keep the menu displayed when we choose an option
  167. menu_display(id, menu);
  168.  
  169. return PLUGIN_HANDLED;
  170. }
  171.  
  172. public npc_TakeDamage(iEnt, inflictor, attacker, Float:damage, bits)
  173. {
  174. //Make sure we only catch our NPC by checking the classname
  175. new className[32];
  176. entity_get_string(iEnt, EV_SZ_classname, className, charsmax(className))
  177.  
  178. if(!equali(className, g_NpcClassName))
  179. return;
  180.  
  181. //Play a random animation when damanged
  182. Util_PlayAnimation(iEnt, random_num(13, 17), 1.25);
  183.  
  184. //Make our NPC say something when it is damaged
  185. //NOTE: Interestingly... Our NPC mouth (which is a controller) moves!! That saves us some work!!
  186. emit_sound(iEnt, CHAN_VOICE, g_NpcSoundPain[random(sizeof g_NpcSoundPain)], VOL_NORM, ATTN_NORM, 0, PITCH_NORM)
  187.  
  188. g_Hit[attacker] = true;
  189. }
  190.  
  191. public npc_Killed(iEnt)
  192. {
  193. new className[32];
  194. entity_get_string(iEnt, EV_SZ_classname, className, charsmax(className))
  195.  
  196. if(!equali(className, g_NpcClassName))
  197. return HAM_IGNORED;
  198.  
  199. //Player a death animation once our NPC is killed
  200. Util_PlayAnimation(iEnt, random_num(25, 30))
  201.  
  202. //Because our NPC may look like it is laying down.
  203. //The bounding box size is still there and it is impossible to change it so we will make the solid of our NPC to nothing
  204. entity_set_int(iEnt, EV_INT_solid, SOLID_NOT);
  205.  
  206. //The voice of the NPC when it is dead
  207. emit_sound(iEnt, CHAN_VOICE, g_NpcSoundDeath[random(sizeof g_NpcSoundDeath)], VOL_NORM, ATTN_NORM, 0, PITCH_NORM)
  208.  
  209. //Our NPC is dead so it shouldn't take any damage and play any animations
  210. entity_set_float(iEnt, EV_FL_takedamage, 0.0);
  211. //Our death boolean should now be true!!
  212. g_NpcDead[iEnt] = true;
  213.  
  214. //The most important part of this forward!! We have to block the death forward.
  215. return HAM_SUPERCEDE
  216. }
  217.  
  218. public npc_Think(iEnt)
  219. {
  220. if(!is_valid_ent(iEnt))
  221. return;
  222.  
  223. static className[32];
  224. entity_get_string(iEnt, EV_SZ_classname, className, charsmax(className))
  225.  
  226. if(!equali(className, g_NpcClassName))
  227. return;
  228.  
  229. //We can remove our NPC here if we wanted to but I left this blank as I personally like it when there is a NPC coprse laying around
  230. if(g_NpcDead[iEnt])
  231. {
  232. return;
  233. }
  234.  
  235. //Our NPC just spawned
  236. if(g_NpcSpawn[iEnt])
  237. {
  238. static Float: mins[3], Float: maxs[3];
  239. pev(iEnt, pev_absmin, mins);
  240. pev(iEnt, pev_absmax, maxs);
  241.  
  242. //Draw a box which is the size of the bounding NPC
  243. message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
  244. write_byte(TE_BOX)
  245. engfunc(EngFunc_WriteCoord, mins[0])
  246. engfunc(EngFunc_WriteCoord, mins[1])
  247. engfunc(EngFunc_WriteCoord, mins[2])
  248. engfunc(EngFunc_WriteCoord, maxs[0])
  249. engfunc(EngFunc_WriteCoord, maxs[1])
  250. engfunc(EngFunc_WriteCoord, maxs[2])
  251. write_short(100)
  252. write_byte(random_num(25, 255))
  253. write_byte(random_num(25, 255))
  254. write_byte(random_num(25, 255))
  255. message_end();
  256.  
  257. //Our NPC spawn boolean is now set to false
  258. g_NpcSpawn[iEnt] = false;
  259. }
  260.  
  261. //Choose a random idle animation
  262. Util_PlayAnimation(iEnt, NPC_IdleAnimations[random(sizeof NPC_IdleAnimations)]);
  263.  
  264. //Make our NPC think every so often
  265. entity_set_float(iEnt, EV_FL_nextthink, get_gametime() + random_float(5.0, 10.0));
  266. }
  267.  
  268. public npc_TraceAttack(iEnt, attacker, Float: damage, Float: direction[3], trace, damageBits)
  269. {
  270. if(!is_valid_ent(iEnt))
  271. return;
  272.  
  273. new className[32];
  274. entity_get_string(iEnt, EV_SZ_classname, className, charsmax(className))
  275.  
  276. if(!equali(className, g_NpcClassName))
  277. return;
  278.  
  279. //Retrieve the end of the trace
  280. new Float: end[3]
  281. get_tr2(trace, TR_vecEndPos, end);
  282.  
  283. //This message will draw blood sprites at the end of the trace
  284. message_begin(MSG_BROADCAST,SVC_TEMPENTITY)
  285. write_byte(TE_BLOODSPRITE)
  286. engfunc(EngFunc_WriteCoord, end[0])
  287. engfunc(EngFunc_WriteCoord, end[1])
  288. engfunc(EngFunc_WriteCoord, end[2])
  289. write_short(spr_blood_spray)
  290. write_short(spr_blood_drop)
  291. write_byte(247) // color index
  292. write_byte(random_num(1, 5)) // size
  293. message_end()
  294. }
  295.  
  296. public npc_ObjectCaps(id)
  297. {
  298. //Make sure player is alive
  299. if(!is_user_alive(id))
  300. return;
  301.  
  302. //Check when player presses +USE key
  303. if(get_user_button(id) & IN_USE)
  304. {
  305. //Check cooldown of player when using our NPC
  306. static Float: gametime ; gametime = get_gametime();
  307. if(gametime - 1.0 > g_Cooldown[id])
  308. {
  309. //Get the classname of whatever ent we are looking at
  310. static iTarget, iBody, szAimingEnt[32];
  311. get_user_aiming(id, iTarget, iBody, 75);
  312. entity_get_string(iTarget, EV_SZ_classname, szAimingEnt, charsmax(szAimingEnt));
  313.  
  314. //Make sure our aim is looking at a NPC
  315. if(equali(szAimingEnt, g_NpcClassName))
  316. {
  317. //Do more fancy stuff here such as opening a menu
  318. //But for this tutorial I will only display a message to prove it works
  319. client_print(id, print_chat, "Hello");
  320. }
  321.  
  322. //Set players cooldown to the current gametime
  323. g_Cooldown[id] = gametime;
  324. }
  325. }
  326. }
  327.  
  328. public npc_EmitSound(id, channel, sample[], Float:volume, Float:attn, flag, pitch)
  329. {
  330. //Make sure player is alive
  331. if(!is_user_connected(id))
  332. return FMRES_SUPERCEDE;
  333.  
  334. //Catch the current button player is pressing
  335. new iButton = get_user_button(id);
  336.  
  337. //If the player knifed the NPC
  338. if(g_Hit[id])
  339. {
  340. //Catch the string and make sure its a knife
  341. if (sample[0] == 'w' && sample[1] == 'e' && sample[8] == 'k' && sample[9] == 'n')
  342. {
  343. //Catch the file of _hitwall1.wav or _slash1.wav/_slash2.wav
  344. if(sample[17] == 's' || sample[17] == 'w')
  345. {
  346. //If player is slashing then play the knife hit sound
  347. if(iButton & IN_ATTACK)
  348. {
  349. emit_sound(id, CHAN_WEAPON, g_NpcSoundKnifeHit[random(sizeof g_NpcSoundKnifeHit)], volume, attn, flag, pitch);
  350. }
  351. //If player is tabbing then play the stab sound
  352. else if(iButton & IN_ATTACK2)
  353. {
  354. emit_sound(id,CHAN_WEAPON, g_NpcSoundKnifeStab, volume, attn, flag, pitch);
  355. }
  356.  
  357. //Reset our boolean as player is not hitting NPC anymore
  358. g_Hit[id] = false;
  359.  
  360. //Block any further sounds to be played
  361. return FMRES_SUPERCEDE
  362. }
  363. }
  364. }
  365.  
  366. return FMRES_IGNORED
  367. }
  368.  
  369. public Event_NewRound()
  370. {
  371. new iEnt = -1;
  372.  
  373. //Scan and find all of the NPC classnames
  374. while( ( iEnt = find_ent_by_class(iEnt, g_NpcClassName) ) )
  375. {
  376. //If we find a NPC which is dead...
  377. if(g_NpcDead[iEnt])
  378. {
  379. //Reset the solid box
  380. entity_set_int(iEnt, EV_INT_solid, SOLID_BBOX);
  381. //Make our NPC able to take damage again
  382. entity_set_float(iEnt, EV_FL_takedamage, 1.0);
  383. //Make our NPC instanstly think
  384. entity_set_float(iEnt, EV_FL_nextthink, get_gametime() + 0.01);
  385.  
  386. //Reset the NPC boolean to false
  387. g_NpcDead[iEnt] = false;
  388. }
  389.  
  390. //Reset the health of our NPC
  391. entity_set_float(iEnt, EV_FL_health, 250.0);
  392. }
  393. }
  394.  
  395. Create_Npc(id, Float:flOrigin[3]= { 0.0, 0.0, 0.0 }, Float:flAngle[3]= { 0.0, 0.0, 0.0 } )
  396. {
  397. //Create an entity using type 'info_target'
  398. new iEnt = create_entity("info_target");
  399.  
  400. //Set our entity to have a classname so we can filter it out later
  401. entity_set_string(iEnt, EV_SZ_classname, g_NpcClassName);
  402.  
  403. //If a player called this function
  404. if(id)
  405. {
  406. //Retrieve the player's origin
  407. entity_get_vector(id, EV_VEC_origin, flOrigin);
  408. //Set the origin of the NPC to the current players location
  409. entity_set_origin(iEnt, flOrigin);
  410. //Increase the Z-Axis by 80 and set our player to that location so they won't be stuck
  411. flOrigin[2] += 80.0;
  412. entity_set_origin(id, flOrigin);
  413.  
  414. //Retrieve the player's angle
  415. entity_get_vector(id, EV_VEC_angles, flAngle);
  416. //Make sure the pitch is zeroed out
  417. flAngle[0] = 0.0;
  418. //Set our NPC angle based on the player's angle
  419. entity_set_vector(iEnt, EV_VEC_angles, flAngle);
  420. }
  421. //If we are reading from a file
  422. else
  423. {
  424. //Set the origin and angle based on the values of the parameters
  425. entity_set_origin(iEnt, flOrigin);
  426. entity_set_vector(iEnt, EV_VEC_angles, flAngle);
  427. }
  428.  
  429. //Set our NPC to take damange and how much health it has
  430. entity_set_float(iEnt, EV_FL_takedamage, 1.0);
  431. entity_set_float(iEnt, EV_FL_health, 250.0);
  432.  
  433. //Set a model for our NPC
  434. entity_set_model(iEnt, g_NpcModel);
  435. //Set a movetype for our NPC
  436. entity_set_int(iEnt, EV_INT_movetype, MOVETYPE_PUSHSTEP);
  437. //Set a solid for our NPC
  438. entity_set_int(iEnt, EV_INT_solid, SOLID_BBOX);
  439.  
  440.  
  441. //Create a bounding box for oru NPC
  442. new Float: mins[3] = {-12.0, -12.0, 0.0 }
  443. new Float: maxs[3] = { 12.0, 12.0, 75.0 }
  444.  
  445. entity_set_size(iEnt, mins, maxs);
  446.  
  447. //Controllers for our NPC. First controller is head. Set it so it looks infront of itself
  448. entity_set_byte(iEnt,EV_BYTE_controller1,125);
  449. // entity_set_byte(ent,EV_BYTE_controller2,125);
  450. // entity_set_byte(ent,EV_BYTE_controller3,125);
  451. // entity_set_byte(ent,EV_BYTE_controller4,125);
  452.  
  453. //Drop our NPC to the floor
  454. drop_to_floor(iEnt);
  455.  
  456. // set_rendering( ent, kRenderFxDistort, 0, 0, 0, kRenderTransAdd, 127 );
  457.  
  458. //We just spawned our NPC so it should not be dead
  459. g_NpcSpawn[iEnt] = true;
  460. g_NpcDead[iEnt] = false;
  461.  
  462. //Make it instantly think
  463. entity_set_float(iEnt, EV_FL_nextthink, get_gametime() + 0.01)
  464. }
  465.  
  466. Load_Npc()
  467. {
  468. //Get the correct filepath and mapname
  469. new szConfigDir[256], szFile[256], szNpcDir[256];
  470.  
  471. get_configsdir(szConfigDir, charsmax(szConfigDir));
  472.  
  473. new szMapName[32];
  474. get_mapname(szMapName, charsmax(szMapName));
  475.  
  476. formatex(szNpcDir, charsmax(szNpcDir),"%s/NPC", szConfigDir);
  477. formatex(szFile, charsmax(szFile), "%s/%s.cfg", szNpcDir, szMapName);
  478.  
  479. //If the filepath does not exist then we will make one
  480. if(!dir_exists(szNpcDir))
  481. {
  482. mkdir(szNpcDir);
  483. }
  484.  
  485. //If the map config file does not exist we will make one
  486. if(!file_exists(szFile))
  487. {
  488. write_file(szFile, "");
  489. }
  490.  
  491. //Variables to store when reading our file
  492. new szFileOrigin[3][32]
  493. new sOrigin[128], sAngle[128];
  494. new Float:fOrigin[3], Float:fAngles[3];
  495. new iLine, iLength, sBuffer[256];
  496.  
  497. //When we are reading our file...
  498. while(read_file(szFile, iLine++, sBuffer, charsmax(sBuffer), iLength))
  499. {
  500. //Move to next line if the line is commented
  501. if((sBuffer[0]== ';') || !iLength)
  502. continue;
  503.  
  504. //Split our line so we have origin and angle. The split is the vertical bar character
  505. strtok(sBuffer, sOrigin, charsmax(sOrigin), sAngle, charsmax(sAngle), '|', 0);
  506.  
  507. //Store the X, Y and Z axis to our variables made earlier
  508. parse(sOrigin, szFileOrigin[0], charsmax(szFileOrigin[]), szFileOrigin[1], charsmax(szFileOrigin[]), szFileOrigin[2], charsmax(szFileOrigin[]));
  509.  
  510. fOrigin[0] = str_to_float(szFileOrigin[0]);
  511. fOrigin[1] = str_to_float(szFileOrigin[1]);
  512. fOrigin[2] = str_to_float(szFileOrigin[2]);
  513.  
  514. //Store the yawn angle
  515. fAngles[1] = str_to_float(sAngle[1]);
  516.  
  517. //Create our NPC
  518. Create_Npc(0, fOrigin, fAngles)
  519.  
  520. //Keep reading the file until the end
  521. }
  522. }
  523.  
  524. Save_Npc()
  525. {
  526. //Variables
  527. new szConfigsDir[256], szFile[256], szNpcDir[256];
  528.  
  529. //Get the configs directory.
  530. get_configsdir(szConfigsDir, charsmax(szConfigsDir));
  531.  
  532. //Get the current map name
  533. new szMapName[32];
  534. get_mapname(szMapName, charsmax(szMapName));
  535.  
  536. //Format 'szNpcDir' to ../configs/NPC
  537. formatex(szNpcDir, charsmax(szNpcDir),"%s/NPC", szConfigsDir);
  538. //Format 'szFile to ../configs/NPC/mapname.cfg
  539. formatex(szFile, charsmax(szFile), "%s/%s.cfg", szNpcDir, szMapName);
  540.  
  541. //If there is already a .cfg for the current map. Delete it
  542. if(file_exists(szFile))
  543. delete_file(szFile);
  544.  
  545. //Variables
  546. new iEnt = -1, Float:fEntOrigin[3], Float:fEntAngles[3];
  547. new sBuffer[256];
  548.  
  549. //Scan and find all of my custom ents
  550. while( ( iEnt = find_ent_by_class(iEnt, g_NpcClassName) ) )
  551. {
  552. //Get the entities' origin and angle
  553. entity_get_vector(iEnt, EV_VEC_origin, fEntOrigin);
  554. entity_get_vector(iEnt, EV_VEC_angles, fEntAngles);
  555.  
  556. //Format the line of one custom ent.
  557. formatex(sBuffer, charsmax(sBuffer), "%d %d %d | %d", floatround(fEntOrigin[0]), floatround(fEntOrigin[1]), floatround(fEntOrigin[2]), floatround(fEntAngles[1]));
  558.  
  559. //Finally write to the mapname.cfg file and move on to the next line
  560. write_file(szFile, sBuffer, -1);
  561.  
  562. //We are currentlying looping to find all custom ents on the map. If found another ent. Do the above till there is none.
  563. }
  564.  
  565. }
  566.  
  567. stock Util_PlayAnimation(index, sequence, Float: framerate = 1.0)
  568. {
  569. entity_set_float(index, EV_FL_animtime, get_gametime());
  570. entity_set_float(index, EV_FL_framerate, framerate);
  571. entity_set_float(index, EV_FL_frame, 0.0);
  572. entity_set_int(index, EV_INT_sequence, sequence);
  573. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement