xuqiang52133
|
分享:
▼
x0
|
[插件] NPC不能自动判断攻击,带源码
(NPC不能自动判断攻击,带源码(求帮助啊))
#include <amxmodx> #include <amxmisc> #include <fakemeta> #include <engine> #include <hamsandwich>
//Boolean of when NPC spawned new bool: g_NpcSpawn[256]; //Boolean to check if NPC is alive or not new bool: g_NpcDead[256]; //Classname for our NPC new const g_NpcClassName[] = "ent_npc"; //Constant model for NPC new const g_NpcModel[] = "models/barney.mdl";
//List of sounds our NPC will emit when damaged new const g_NpcSoundPain[][] = { "barney/ba_pain1.wav", "barney/ba_pain2.wav", "barney/ba_pain3.wav" }
//Sounds when killed new const g_NpcSoundDeath[][] = { "barney/ba_die1.wav", "barney/ba_die2.wav", "barney/ba_die3.wav" }
//Sounds when we knife our flesh NPC new const g_NpcSoundKnifeHit[][] = { "weapons/knife_hit1.wav", "weapons/knife_hit2.wav", "weapons/knife_hit3.wav", "weapons/knife_hit4.wav" }
new const g_NpcSoundKnifeStab[] = "weapons/knife_stab.wav";
//List of idle animations new const NPC_IdleAnimations[] = { 0, 1, 2, 3, 11, 12, 18, 21, 39, 63, 65 };
//Sprites for blood when our NPC is damaged new spr_blood_drop, spr_blood_spray
//Player cooldown for using our NPC new Float: g_Cooldown[32];
//Boolean to check if we knifed our NPC new bool: g_Hit[32];
public plugin_init() { register_plugin("NPC Plugin", "1.1", "Mazza"); register_clcmd("say /npc", "ClCmd_NPC"); register_event("HLTV", "Event_NewRound", "a", "1=0", "2=0"); RegisterHam(Ham_TakeDamage, "info_target", "npc_TakeDamage"); RegisterHam(Ham_Killed, "info_target", "npc_Killed"); RegisterHam(Ham_Think, "info_target", "npc_Think"); RegisterHam(Ham_TraceAttack, "info_target", "npc_TraceAttack"); RegisterHam(Ham_ObjectCaps, "player", "npc_ObjectCaps", 1 ); register_forward(FM_EmitSound, "npc_EmitSound"); }
public plugin_precache() { spr_blood_drop = precache_model("sprites/blood.spr") spr_blood_spray = precache_model("sprites/bloodspray.spr") new i; for(i = 0 ; i < sizeof g_NpcSoundPain ; i++) precache_sound(g_NpcSoundPain); for(i = 0 ; i < sizeof g_NpcSoundDeath ; i++) precache_sound(g_NpcSoundDeath);
precache_model(g_NpcModel) }
public plugin_cfg() { Load_Npc() }
public ClCmd_NPC(id) { //Create a new menu new menu = menu_create("NPC: 菜单", "Menu_Handler"); //Add some items to the newly created menu menu_additem(menu, "建立NPC", "1"); menu_additem(menu, "删除NPC", "2"); menu_additem(menu, "保存所有NPC", "3"); menu_additem(menu, "删除所有NPC", "4"); //Let the menu have an 'Exit' option menu_setprop(menu, MPROP_EXIT, MEXIT_ALL); //Display our menu menu_display(id, menu); }
public Menu_Handler(id, menu, item) { //If user chose to exit menu we will destroy our menu if(item == MENU_EXIT) { menu_destroy(menu); return PLUGIN_HANDLED; } new info[6], szName[64]; new access, callback; menu_item_getinfo(menu, item, access, info, charsmax(info), szName, charsmax(szName), callback); new key = str_to_num(info); switch(key) { case 1: { //Create our NPC Create_Npc(id); } case 2: { //Remove our NPC by the users aim new iEnt, body, szClassname[32]; get_user_aiming(id, iEnt, body); if (is_valid_ent(iEnt)) { entity_get_string(iEnt, EV_SZ_classname, szClassname, charsmax(szClassname)); if (equal(szClassname, g_NpcClassName)) { remove_entity(iEnt); } } } case 3: { //Save the current locations of all the NPCs Save_Npc(); client_print(id, print_chat, "[AMXX] 已经保存"); } case 4: { //Remove all NPCs from the map remove_entity_name(g_NpcClassName); client_print(id, print_chat, "[AMXX] 已经删除"); } } //Keep the menu displayed when we choose an option menu_display(id, menu); return PLUGIN_HANDLED; }
public npc_TakeDamage(iEnt, inflictor, attacker, Float:damage, bits) { //Make sure we only catch our NPC by checking the classname new className[32]; entity_get_string(iEnt, EV_SZ_classname, className, charsmax(className)) if(!equali(className, g_NpcClassName)) return; //Play a random animation when damanged Util_PlayAnimation(iEnt, random_num(13, 17), 1.25);
//Make our NPC say something when it is damaged //NOTE: Interestingly... Our NPC mouth (which is a controller) moves!! That saves us some work!! emit_sound(iEnt, CHAN_VOICE, g_NpcSoundPain[random(sizeof g_NpcSoundPain)], VOL_NORM, ATTN_NORM, 0, PITCH_NORM) g_Hit[attacker] = true; }
public npc_Killed(iEnt) { new className[32]; entity_get_string(iEnt, EV_SZ_classname, className, charsmax(className)) if(!equali(className, g_NpcClassName)) return HAM_IGNORED;
//Player a death animation once our NPC is killed Util_PlayAnimation(iEnt, random_num(25, 30))
//Because our NPC may look like it is laying down. //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 entity_set_int(iEnt, EV_INT_solid, SOLID_NOT);
//The voice of the NPC when it is dead emit_sound(iEnt, CHAN_VOICE, g_NpcSoundDeath[random(sizeof g_NpcSoundDeath)], VOL_NORM, ATTN_NORM, 0, PITCH_NORM)
//Our NPC is dead so it shouldn't take any damage and play any animations entity_set_float(iEnt, EV_FL_takedamage, 0.0); //Our death boolean should now be true!! g_NpcDead[iEnt] = true; //The most important part of this forward!! We have to block the death forward. return HAM_SUPERCEDE }
public npc_Think(iEnt) { if(!is_valid_ent(iEnt)) return; static className[32]; entity_get_string(iEnt, EV_SZ_classname, className, charsmax(className)) if(!equali(className, g_NpcClassName)) return; //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 if(g_NpcDead[iEnt]) { return; } //Our NPC just spawned if(g_NpcSpawn[iEnt]) { static Float: mins[3], Float: maxs[3]; pev(iEnt, pev_absmin, mins); pev(iEnt, pev_absmax, maxs);
//Draw a box which is the size of the bounding NPC message_begin(MSG_BROADCAST, SVC_TEMPENTITY) write_byte(TE_BOX) engfunc(EngFunc_WriteCoord, mins[0]) engfunc(EngFunc_WriteCoord, mins[1]) engfunc(EngFunc_WriteCoord, mins[2]) engfunc(EngFunc_WriteCoord, maxs[0]) engfunc(EngFunc_WriteCoord, maxs[1]) engfunc(EngFunc_WriteCoord, maxs[2]) write_short(100) write_byte(random_num(25, 255)) write_byte(random_num(25, 255)) write_byte(random_num(25, 255)) message_end(); //Our NPC spawn boolean is now set to false g_NpcSpawn[iEnt] = false; } //Choose a random idle animation Util_PlayAnimation(iEnt, NPC_IdleAnimations[random(sizeof NPC_IdleAnimations)]);
//Make our NPC think every so often entity_set_float(iEnt, EV_FL_nextthink, get_gametime() + random_float(5.0, 10.0)); }
public npc_TraceAttack(iEnt, attacker, Float: damage, Float: direction[3], trace, damageBits) { if(!is_valid_ent(iEnt)) return; new className[32]; entity_get_string(iEnt, EV_SZ_classname, className, charsmax(className)) if(!equali(className, g_NpcClassName)) return; //Retrieve the end of the trace new Float: end[3] get_tr2(trace, TR_vecEndPos, end); //This message will draw blood sprites at the end of the trace message_begin(MSG_BROADCAST,SVC_TEMPENTITY) write_byte(TE_BLOODSPRITE) engfunc(EngFunc_WriteCoord, end[0]) engfunc(EngFunc_WriteCoord, end[1]) engfunc(EngFunc_WriteCoord, end[2]) write_short(spr_blood_spray) write_short(spr_blood_drop) write_byte(247) // color index write_byte(random_num(1, 5)) // size message_end() }
public npc_ObjectCaps(id) { //Make sure player is alive if(!is_user_alive(id)) return;
//Check when player presses +USE key if(get_user_button(id) & IN_USE) { //Check cooldown of player when using our NPC static Float: gametime ; gametime = get_gametime(); if(gametime - 1.0 > g_Cooldown[id]) { //Get the classname of whatever ent we are looking at static iTarget, iBody, szAimingEnt[32]; get_user_aiming(id, iTarget, iBody, 75); entity_get_string(iTarget, EV_SZ_classname, szAimingEnt, charsmax(szAimingEnt)); //Make sure our aim is looking at a NPC if(equali(szAimingEnt, g_NpcClassName)) { //Do more fancy stuff here such as opening a menu //But for this tutorial I will only display a message to prove it works client_print(id, print_chat, "嘿!老兄你看到我的朋友嘎登没有?他到那里去了"); } //Set players cooldown to the current gametime g_Cooldown[id] = gametime; } } }
public npc_EmitSound(id, channel, sample[], Float:volume, Float:attn, flag, pitch) { //Make sure player is alive if(!is_user_connected(id)) return FMRES_SUPERCEDE;
//Catch the current button player is pressing new iButton = get_user_button(id); //If the player knifed the NPC if(g_Hit[id]) { //Catch the string and make sure its a knife if (sample[0] == 'w' && sample[1] == 'e' && sample[8] == 'k' && sample[9] == 'n') { //Catch the file of _hitwall1.wav or _slash1.wav/_slash2.wav if(sample[17] == 's' || sample[17] == 'w') { //If player is slashing then play the knife hit sound if(iButton & IN_ATTACK) { emit_sound(id, CHAN_WEAPON, g_NpcSoundKnifeHit[random(sizeof g_NpcSoundKnifeHit)], volume, attn, flag, pitch); } //If player is tabbing then play the stab sound else if(iButton & IN_ATTACK2) { emit_sound(id,CHAN_WEAPON, g_NpcSoundKnifeStab, volume, attn, flag, pitch); }
//Reset our boolean as player is not hitting NPC anymore g_Hit[id] = false; //Block any further sounds to be played return FMRES_SUPERCEDE } } } return FMRES_IGNORED }
public Event_NewRound() { new iEnt = -1; //Scan and find all of the NPC classnames while( ( iEnt = find_ent_by_class(iEnt, g_NpcClassName) ) ) { //If we find a NPC which is dead... if(g_NpcDead[iEnt]) { //Reset the solid box entity_set_int(iEnt, EV_INT_solid, SOLID_BBOX); //Make our NPC able to take damage again entity_set_float(iEnt, EV_FL_takedamage, 1.0); //Make our NPC instanstly think entity_set_float(iEnt, EV_FL_nextthink, get_gametime() + 0.01); //Reset the NPC boolean to false g_NpcDead[iEnt] = false; } //Reset the health of our NPC entity_set_float(iEnt, EV_FL_health, 250.0); } }
Create_Npc(id, Float:flOrigin[3]= { 0.0, 0.0, 0.0 }, Float:flAngle[3]= { 0.0, 0.0, 0.0 } ) { //Create an entity using type 'info_target' new iEnt = create_entity("info_target"); //Set our entity to have a classname so we can filter it out later entity_set_string(iEnt, EV_SZ_classname, g_NpcClassName); //If a player called this function if(id) { //Retrieve the player's origin entity_get_vector(id, EV_VEC_origin, flOrigin); //Set the origin of the NPC to the current players location entity_set_origin(iEnt, flOrigin); //Increase the Z-Axis by 80 and set our player to that location so they won't be stuck flOrigin[2] += 80.0; entity_set_origin(id, flOrigin); //Retrieve the player's angle entity_get_vector(id, EV_VEC_angles, flAngle); //Make sure the pitch is zeroed out flAngle[0] = 0.0; //Set our NPC angle based on the player's angle entity_set_vector(iEnt, EV_VEC_angles, flAngle); } //If we are reading from a file else { //Set the origin and angle based on the values of the parameters entity_set_origin(iEnt, flOrigin); entity_set_vector(iEnt, EV_VEC_angles, flAngle); }
//Set our NPC to take damange and how much health it has entity_set_float(iEnt, EV_FL_takedamage, 1.0); entity_set_float(iEnt, EV_FL_health, 250.0);
//Set a model for our NPC entity_set_model(iEnt, g_NpcModel); //Set a movetype for our NPC entity_set_int(iEnt, EV_INT_movetype, MOVETYPE_PUSHSTEP); //Set a solid for our NPC entity_set_int(iEnt, EV_INT_solid, SOLID_BBOX); //Create a bounding box for oru NPC new Float: mins[3] = {-12.0, -12.0, 0.0 } new Float: maxs[3] = { 12.0, 12.0, 75.0 }
entity_set_size(iEnt, mins, maxs); //Controllers for our NPC. First controller is head. Set it so it looks infront of itself entity_set_byte(iEnt,EV_BYTE_controller1,125); // entity_set_byte(ent,EV_BYTE_controller2,125); // entity_set_byte(ent,EV_BYTE_controller3,125); // entity_set_byte(ent,EV_BYTE_controller4,125); //Drop our NPC to the floor drop_to_floor(iEnt); // set_rendering( ent, kRenderFxDistort, 0, 0, 0, kRenderTransAdd, 127 ); //We just spawned our NPC so it should not be dead g_NpcSpawn[iEnt] = true; g_NpcDead[iEnt] = false; //Make it instantly think entity_set_float(iEnt, EV_FL_nextthink, get_gametime() + 0.01) }
Load_Npc() { //Get the correct filepath and mapname new szConfigDir[256], szFile[256], szNpcDir[256]; get_configsdir(szConfigDir, charsmax(szConfigDir)); new szMapName[32]; get_mapname(szMapName, charsmax(szMapName)); formatex(szNpcDir, charsmax(szNpcDir),"%s/NPC", szConfigDir); formatex(szFile, charsmax(szFile), "%s/%s.cfg", szNpcDir, szMapName); //If the filepath does not exist then we will make one if(!dir_exists(szNpcDir)) { mkdir(szNpcDir); } //If the map config file does not exist we will make one if(!file_exists(szFile)) { write_file(szFile, ""); } //Variables to store when reading our file new szFileOrigin[3][32] new sOrigin[128], sAngle[128]; new Float:fOrigin[3], Float:fAngles[3]; new iLine, iLength, sBuffer[256]; //When we are reading our file... while(read_file(szFile, iLine++, sBuffer, charsmax(sBuffer), iLength)) { //Move to next line if the line is commented if((sBuffer[0]== ';') || !iLength) continue; //Split our line so we have origin and angle. The split is the vertical bar character strtok(sBuffer, sOrigin, charsmax(sOrigin), sAngle, charsmax(sAngle), '|', 0); //Store the X, Y and Z axis to our variables made earlier parse(sOrigin, szFileOrigin[0], charsmax(szFileOrigin[]), szFileOrigin[1], charsmax(szFileOrigin[]), szFileOrigin[2], charsmax(szFileOrigin[])); fOrigin[0] = str_to_float(szFileOrigin[0]); fOrigin[1] = str_to_float(szFileOrigin[1]); fOrigin[2] = str_to_float(szFileOrigin[2]); //Store the yawn angle fAngles[1] = str_to_float(sAngle[1]); //Create our NPC Create_Npc(0, fOrigin, fAngles) //Keep reading the file until the end } }
Save_Npc() { //Variables new szConfigsDir[256], szFile[256], szNpcDir[256]; //Get the configs directory. get_configsdir(szConfigsDir, charsmax(szConfigsDir)); //Get the current map name new szMapName[32]; get_mapname(szMapName, charsmax(szMapName)); //Format 'szNpcDir' to ../configs/NPC formatex(szNpcDir, charsmax(szNpcDir),"%s/NPC", szConfigsDir); //Format 'szFile to ../configs/NPC/mapname.cfg formatex(szFile, charsmax(szFile), "%s/%s.cfg", szNpcDir, szMapName); //If there is already a .cfg for the current map. Delete it if(file_exists(szFile)) delete_file(szFile); //Variables new iEnt = -1, Float:fEntOrigin[3], Float:fEntAngles[3]; new sBuffer[256]; //Scan and find all of my custom ents while( ( iEnt = find_ent_by_class(iEnt, g_NpcClassName) ) ) { //Get the entities' origin and angle entity_get_vector(iEnt, EV_VEC_origin, fEntOrigin); entity_get_vector(iEnt, EV_VEC_angles, fEntAngles); //Format the line of one custom ent. formatex(sBuffer, charsmax(sBuffer), "%d %d %d | %d", floatround(fEntOrigin[0]), floatround(fEntOrigin[1]), floatround(fEntOrigin[2]), floatround(fEntAngles[1])); //Finally write to the mapname.cfg file and move on to the next line write_file(szFile, sBuffer, -1); //We are currentlying looping to find all custom ents on the map. If found another ent. Do the above till there is none. } }
stock Util_PlayAnimation(index, sequence, Float: framerate = 1.0) { entity_set_float(index, EV_FL_animtime, get_gametime()); entity_set_float(index, EV_FL_framerate, framerate); entity_set_float(index, EV_FL_frame, 0.0); entity_set_int(index, EV_INT_sequence, sequence); }
|