NPC, Non Player Character yani Türkçe karşılığı ile Oyuncu olmayan karakterdir. Bu derste ayrıntılı bir şekilde açıklayarak anlatacağım. Bu ders biraz ileri seviye olabilir. Düzenleyerek kullana kullana öğrenebilirsiniz. Bunun için bilinmesi gereken kütüphaneler,
fakemeta,
engine,
hamsandwich
Fakemeta ve engine kütüphaneleri kod bakımından birbirine çok benzer ama çalışma mantıkları farklıdır. Evet zor kütüphaneler ama ingilizce oldukları ve Türkçe kaynak olmadığı için zor geliyor. Mantığını kavrayabilirsek eğlenceli hale gelebiliyor.
Gelelim konumuza, NPC yani oyuncu olmayan karakter, adından da anlaşılacağı gibi herhangi bir oyuncu tarafındandan yönetilmez, sanal zekadır. Çoğu oyunda karşılaşırız mesela en anlamlı örnek, Half-Life' da karşılaştığımız her yaratık, insan, bilim adamı vb. birer NPC dir. Yönetilmezler. Onlar için daha önceden belirlenmiş belli başlı görevleri yaparlar. Bizde CS' de bu şekilde NPC yapabiliriz. Peki NPC ile neler yapabiliriz? Oyun içinde bir market, size sadık bir köpek, bir zombi, size yardım eden bir asker vb. bu şekilde sırayabiliriz. Yani bu NPC işiyle ortaya çok eğlenceli işler çıkabiliyor.
Bu derste biz NPC' ye ne yaptıracağız?
*NPC' yi öldürebileceğiz.
*NPC' yi konuşturacağız.
*NPC'yi hareket ettireceğiz.( şimdilik olduğu yerde )
Öncelikle gerekli kütüphaneleri girelim.
PHP- Kodu:
#include <amxmodx>
#include <amxmisc>
#include <fakemeta>
#include <engine>
#include <hamsandwich>
Şimdi de plugin için gerekli değişken ve sabit değerleri tanımlıyoruz. Burada NPC için ses, model ve sayısal değişkenleri tanımlayacağız. Buradaki sesleri değiştirebilirsiniz. Ancak modeli değiştirirseniz animasyonlar farklı olabileceği için sorun çıkabilir. Farklı modeller kullanacaksanız Jed's Half-Life Model Viewer programını kullanarak model için gerekli animasyonları seçebilirsiniz. Bunun için de programda bulunan squences bölümünü açın ve oradan hareketi seçip squence# nin karşısındaki sayıyı not alın. Bu sayı model için o hareketin değeridir. Daha sonra değişkendeki sayı değerini not aldığınız sayı ile değiştirebilirsiniz.
PHP- Kodu:
#define PLUGIN "NPC - Non Playar Character - Oyuncu Olmayan Karakter"
#define VERSION "1.0"
#define AUTHOR "peNgueN"
//NPC oldu mu yasiyor mu ?
new bool: g_NpcOldu[ 512 ];
//NPC Entity Ismi
new const NpcClass[] = "entity_npc";
//NPC Hareketleri
new const g_NpcIdleAnimations[] = { 13, 14, 15, 16, 17 }; //NPC Durus Animasyonlari
new const g_NpcDamageAnimations[] = { 8, 9, 10 }; //NPC Hasar Animasyonlari
new const g_NpcDeathAnimations[] = { 31, 32, 33, 34, 35, 36 }; //NPC Olum Animasyonlari
new const g_NpcTalkAnimations[] = { 59, 60, 61, 62, 63 }; //NPC Konusma Hareketleri
//NPC kan efektleri
new npc_kan_spr, npc_kan_spr_sprey;
//NPC Modeli
new const g_NpcModel[] = "models/hostage.mdl";
//NPC Sayisi
new NpcSayisi;
//NPC Sesleri
new const g_NpcOlumSesi[][] = {
"barney/ba_die1.wav",
"barney/ba_die2.wav",
"barney/ba_die3.wav"
}
new const g_NpcHasarSesi[][] = {
"barney/ba_pain1.wav",
"barney/ba_pain2.wav",
"barney/ba_pain3.wav"
}
new const g_NpcKonusma[][] = {
"barney/dontaskme.wav",
"barney/haybuddy.wav",
"barney/hayfella.wav",
"barney/hellonicesuit.wav",
"barney/howyoudoing.wav"
}
Daha sonra plugin başlangıcını yazıyoruz.( plugin_init ) Burada NPC için gerekli kodları gireceğiz ve model, sesleri yükleyeceğiz.
PHP- Kodu:
public plugin_init()
{
register_plugin( PLUGIN, VERSION, AUTHOR );
//NPC Kontrol Menusu
register_clcmd( "say /npc", "NpcMenu" );
register_clcmd( "say_team /npc", "NpcMenu" );
//NPC Kontrol Fonksiyonlari
RegisterHam( Ham_TakeDamage, "info_target", "fw_NpcTakeDamage" ); //Hasar Fonksiyonu
RegisterHam( Ham_Killed, "info_target", "fw_NpcKilled" ); //Olum Fonksiyonu
RegisterHam( Ham_Think, "info_target", "fw_NpcThink" ); //Beyin Fonksiyonu
RegisterHam( Ham_TraceAttack, "info_target", "fw_NpcTraceAttack" ); //Mermi Fonksiyonu
RegisterHam( Ham_Touch, "info_target", "fw_NpcTouch" ); //Dokunma Fonksiyonu
}
public plugin_precache( )
{
npc_kan_spr = precache_model( "sprites/blood.spr" );
npc_kan_spr_sprey = precache_model( "sprites/bloodspray.spr" );
precache_model( g_NpcModel );
for( new i = 0 ; i < sizeof g_NpcOlumSesi ; i++)
precache_sound( g_NpcOlumSesi[ i ] );
for( new i = 0 ; i < sizeof g_NpcHasarSesi ; i++)
precache_sound( g_NpcHasarSesi[ i ] );
for( new i = 0 ; i < sizeof g_NpcKonusma ; i++)
precache_sound( g_NpcKonusma[ i ] );
}
Şimdi NPC için kontrol menüsü yapalım. NPC oluşturup, kaldırabilmek için.
PHP- Kodu:
public NpcMenu( id )
{
new iMenu[ 64 ];
formatex( iMenu, charsmax( iMenu ), "NPC - Oyuncu Olmayan Karakter" );
new menu = menu_create( iMenu, "NpcMenu_go" );
formatex( iMenu, charsmax( iMenu ), "\wNPC Olustur \y( Aim ile yer belirleyin )" );
menu_additem( menu, iMenu, "1" );
formatex( iMenu, charsmax( iMenu ), "\wNPC Kaldir \y( Aim ile secin )" );
menu_additem( menu, iMenu, "2" );
formatex( iMenu, charsmax( iMenu ), "\wButun NPC'leri Kaldir^n \y %d NPC Mevcut", NpcSayisi );
menu_additem( menu, iMenu, "3" );
menu_setprop( menu, MPROP_EXIT, MEXIT_ALL);
menu_setprop( menu, MPROP_EXITNAME, "\rCIKIS" );
menu_display(id, menu);
return PLUGIN_HANDLED;
}
public NpcMenu_go( id, menu, item )
{
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:
{
if( !is_user_alive( id ) ) return PLUGIN_HANDLED;
NpcOlustur( id );
}
case 2:
{
if( !is_user_alive( id ) ) return PLUGIN_HANDLED;
new iEnt, Vucut, NPC[ 64 ];
get_user_aiming( id, iEnt, Vucut );
if ( is_valid_ent( iEnt ) )
{
entity_get_string( iEnt, EV_SZ_classname, NPC, charsmax( NPC ) );
if ( equal( NPC, NpcClass ) )
{
remove_entity( iEnt );
NpcSayisi--;
client_print( id, print_chat, "[NPC] Bir NPC Kaldirildi." );
}
}
}
case 3:
{
remove_entity_name( NpcClass );
NpcSayisi = 0;
client_print( id, print_chat, "[NPC] Butun NPC'ler Kaldirildi." );
}
}
menu_destroy(menu);
return PLUGIN_HANDLED;
}
Şimdi de NPC'nin hamsandwich ile oluşturduğumuz kontrol fonksiyonlarını ekleyelim. Burada NPC için, öldürme, dokunma, düşünme ve saldırma fonksiyonları bulunuyor.
PHP- Kodu:
//NPC'ye dokundugumuzda bizmle konusacak ve hareket edecek.
public fw_NpcTouch( iEnt, id )
{
if( !is_user_alive( id ) )
return HAM_SUPERCEDE;
//Sadece 1 kere çalismasi için kontrol ediyoruz.
static Float: gametime, Float: Cooldown[ 32 ];
gametime = get_gametime();
if(gametime - 1.0 > Cooldown[ id ] )
{
//NPC kontrolu yapiyoruz. Burada NPC mizin ClassName yani ismini sorgulayarak onu baska nesnelerden ayiriyoruz.
//Sadece bizim NPC mizde calismasi icin kontrol ediyoruz. Duvara degdiginde konusmasini istemeyiz :)
new NPC[ 64 ];
entity_get_string( iEnt, EV_SZ_classname, NPC, charsmax( NPC ) );
if( equali( NPC, NpcClass ) )
{
//NPC'ye dokundugumuzda hareket edecek. Hareketleri g_NpcTalkAnimations degiskeninden aldik.
Util_PlayAnimation( iEnt, g_NpcTalkAnimations[ random( sizeof g_NpcTalkAnimations ) ] );
//NPC'ye dokunudugumuzda bizimle konusucak. Sesleri g_NpcKonusma degiskeninden aldik.
emit_sound( iEnt, CHAN_VOICE, g_NpcKonusma[ random( sizeof g_NpcKonusma ) ], VOL_NORM, ATTN_NORM, 0, PITCH_NORM );
}
Cooldown[ id ] = gametime;
}
return HAM_IGNORED;
}
//NPC'ye hasar verdigimizde hareket edecek ve bagiracak.
public fw_NpcTakeDamage( iEnt, inflictor, attacker, Float:damage, bits )
{
//NPC kontrolu yapiyoruz. Burada NPC mizin ClassName yani ismini sorgulayarak onu baska nesnelerden ayiriyoruz.
new NPC[ 64 ];
entity_get_string( iEnt, EV_SZ_classname, NPC, charsmax( NPC ) );
if( equali( NPC, NpcClass ) )
{
//NPC'ye hasar verdigimizde hareket edecek. Hareketleri g_NpcDamageAnimations degiskeninden aldik.
Util_PlayAnimation( iEnt, g_NpcDamageAnimations[ random( sizeof g_NpcDamageAnimations ) ], 1.25 );
//NPC'ye hasar verdigimizde bagiracak. Sesleri g_NpcHasarSesi degiskeninden aldik.
emit_sound( iEnt, CHAN_VOICE, g_NpcHasarSesi[ random( sizeof g_NpcHasarSesi ) ], VOL_NORM, ATTN_NORM, 0, PITCH_NORM );
}
}
//NPC'yi olduruyoruz.
public fw_NpcKilled( iEnt, Killer )
{
new NPC[ 64 ];
entity_get_string( iEnt, EV_SZ_classname, NPC, charsmax( NPC ) );
if( equali( NPC, NpcClass ) )
{
//g_NpcOldu degiskenini dogru tanimladik.
g_NpcOldu[ iEnt ] = true;
//NPC oldugunde olum animasyonu calisacak.
Util_PlayAnimation(iEnt, g_NpcDeathAnimations[ random( sizeof g_NpcDeathAnimations ) ] );
//Oldugunde NPC'nin içinden geçebiliriz. SOLID_NOT entity nin içinden geçilmesini kapatir.
entity_set_int( iEnt, EV_INT_solid, SOLID_NOT );
//NPC'yi olu olarak tanimladik.
entity_set_int( iEnt, EV_INT_deadflag, DEAD_DEAD );
//NPC'nin cesedinin hasar almasini kapattik.
entity_set_float(iEnt, EV_FL_takedamage, 0.0 );
//NPC oldugunde bagiracak.
emit_sound( iEnt, CHAN_VOICE, g_NpcOlumSesi[ random( sizeof g_NpcOlumSesi ) ], VOL_NORM, ATTN_NORM, 0, PITCH_NORM );
client_print( Killer, print_chat, "[NPC] NPC'yi oldurdunuz." );
//NPC oldugunden 5 saniye sonra cesedi yerden silinecek.
set_task( 5.0, "NpcOluyuKaldir", iEnt );
}
return HAM_SUPERCEDE;
}
//NPC'yi kaldir
public NpcOluyuKaldir( Npc )
{
remove_entity( Npc );
}
//NPC'nin dusunme fonksiyonu yani beyni. bu fonksiyon içine NPC mize ne yaptirmak istiyorsaniz ekleyebilirsiniz.
//Biz sadece durmasini istiyoruz bu yuzden NPC miz durmaktan baska bisey yapmayacak.
public fw_NpcThink( iEnt )
{
if( !is_valid_ent( iEnt ) )
return HAM_SUPERCEDE;
new NPC[ 64 ];
entity_get_string( iEnt, EV_SZ_classname, NPC, charsmax( NPC ) );
if( !equali( NPC, NpcClass ) )
return HAM_SUPERCEDE;
//Eger NPC'miz oluyse dusunme fonksiyonunu kapat.
if( g_NpcOldu[ iEnt ] )
return HAM_SUPERCEDE;
//NPC sadece duracak yani durus animasyonu.
Util_PlayAnimation(iEnt, g_NpcIdleAnimations[ random( sizeof g_NpcIdleAnimations ) ] );
//NPC'nin beyni her 5 saniyede bir çalisacak.
entity_set_float( iEnt, EV_FL_nextthink, get_gametime() + 5.0 );
return HAM_IGNORED;
}
//NPC hasar fonksiyonu2, fark, bu fonksiyonda hasarimizin yonunu belirleyebiliyoruz. Bir bu fonksiyonu-
//NPC hasar aldiginda vucudundan kan cikmasi icin kullanacagiz.
public fw_NpcTraceAttack(iEnt, attacker, Float: damage, Float: direction[3], trace, damageBits)
{
if( !is_valid_ent( iEnt ) )
return HAM_SUPERCEDE;
new NPC[ 64 ];
entity_get_string( iEnt, EV_SZ_classname, NPC, charsmax( NPC ) );
if( equali( NPC, NpcClass ) )
{
//NPC hasar alma kapaliysa kan cikmasin.
if( entity_get_float( iEnt, EV_FL_takedamage ) == 0.0 )
return HAM_SUPERCEDE;
//Merminin son carptigi yerin koordinatlarini buluyoruz.
new Float: end[ 3 ];
get_tr2( trace, TR_vecEndPos, end );
//Mermi NPC'nin neresine çarptiysa kan o bolgeden cikacak.
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( npc_kan_spr_sprey );
write_short( npc_kan_spr );
write_byte( 247 );
write_byte( random_num( 5, 15 ) );
message_end();
}
return HAM_IGNORED;
}
NPC için ekstra oluşturduğumuz stockları ekliyoruz. NPC için hareket ve Nişan alınan noktanın koordinatları fonksiyonlarını kullanacağız.
PHP- Kodu:
//NPC icin animasyon,hareket fonksiyonu.
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);
}
//Nisan alinan noktanin koordinatlarini bul. - akcaliberkk
stock get_user_hitpoint(id, Float:hOrigin[3]) {
if ( ! is_user_alive( id ))
return 0;
new Float:fOrigin[3], Float:fvAngle[3], Float:fvOffset[3], Float:fvOrigin[3], Float:feOrigin[3];
new Float:fTemp[3];
pev(id, pev_origin, fOrigin);
pev(id, pev_v_angle, fvAngle);
pev(id, pev_view_ofs, fvOffset);
xs_vec_add(fOrigin, fvOffset, fvOrigin);
engfunc(EngFunc_AngleVectors, fvAngle, feOrigin, fTemp, fTemp);
xs_vec_mul_scalar(feOrigin, 9999.9, feOrigin);
xs_vec_add(fvOrigin, feOrigin, feOrigin);
engfunc(EngFunc_TraceLine, fvOrigin, feOrigin, 0, id);
global_get(glb_trace_endpos, hOrigin);
return 1;
}
ve son olarak NPC'mizi oluşturuyoruz. Kodların üstünde açıkladım bazı değerleri istediğiniz gibi ayarlayabilirsiniz.
PHP- Kodu:
//ve NPC mizi bu fonksiyonda olusturuyoruz.
public NpcOlustur( id )
{
//NPC icin koordinat ve aci degiskenleri olusturduk.
new Float: Origin[ 3 ], Float: Angle[ 3 ];
//Herhangi bir entity yani nesne yaratiyoruz sonra bu nesneyi NPC olarak tanimlayacagiz.
new iEnt = create_entity( "info_target" );
//Yaptigimiz nesneyi bizim NPC miz olarak tanimladik.
entity_set_string( iEnt, EV_SZ_classname, NpcClass );
//Aim ile koordinatlari buluyoruz. NPC miz o koordinatlarda olucak.
get_user_hitpoint( id, Origin );
Origin[ 2 ] += 70.0;
entity_set_origin( iEnt, Origin );
//Oyuncunun bakis acisini aliyoruzki NPC de o acida olussun.
entity_get_vector(id, EV_VEC_angles, Angle );
Angle[ 0 ] = 0.0;
entity_set_vector( iEnt, EV_VEC_angles, Angle );
//NPC mizin modelini ayarliyoruz.
entity_set_model( iEnt, g_NpcModel );
//NPC miz hareketini ayarliyoruz. Yani ittirilebilir bir entity olacak.
entity_set_int(iEnt, EV_INT_movetype, MOVETYPE_PUSHSTEP );
//NPC miz içi dolu bir nesne olucak yani içinden geçemeyiz.
entity_set_int(iEnt, EV_INT_solid, SOLID_BBOX );
//NPC miz hasar alabilir.
entity_set_float( iEnt, EV_FL_takedamage, 1.0 );
//NPC'nin canini 500 yaptik.
entity_set_float( iEnt, EV_FL_health, 500.0 );
//Simdide NPC mizin buyuklugunu ayarliyoruz bu degerler min ve max olarak ayarlanir. 3 boyutlu olarak yani.
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);
//NPC kafasini kontrol edebilir.
entity_set_byte( iEnt, EV_BYTE_controller1, 125 );
//ve NPC mizi yere sabitliyoruz yanlis anlamayin yani havada duvarda vb. yerde olusabilir eger olusursa yere indirir
//bu kod.
drop_to_floor( iEnt );
//NPC mizin canli oldugunu tanimliyoruz.
g_NpcOldu[ iEnt ] = false;
//NPC sayisina +1 ekliyoruz.
NpcSayisi++;
//NPC nin beyni 1 saniye sonra calisacak.
entity_set_float( iEnt, EV_FL_nextthink, get_gametime() + 1.0 );
}
NPC plugininin son hali:
PHP- Kodu:
#include <amxmodx>
#include <amxmisc>
#include <fakemeta>
#include <engine>
#include <hamsandwich>
#define PLUGIN "NPC - Non Playar Character - Oyuncu Olmayan Karakter"
#define VERSION "1.0"
#define AUTHOR "peNgueN"
//NPC oldu mu yasiyor mu ?
new bool: g_NpcOldu[ 512 ];
//NPC Entity Ismi
new const NpcClass[] = "entity_npc";
//NPC Hareketleri
new const g_NpcIdleAnimations[] = { 13, 14, 15, 16, 17 }; //NPC Durus Animasyonlari
new const g_NpcDamageAnimations[] = { 8, 9, 10 }; //NPC Hasar Animasyonlari
new const g_NpcDeathAnimations[] = { 31, 32, 33, 34, 35, 36 }; //NPC Olum Animasyonlari
new const g_NpcTalkAnimations[] = { 59, 60, 61, 62, 63 }; //NPC Konusma Hareketleri
//NPC kan efektleri
new npc_kan_spr, npc_kan_spr_sprey;
//NPC Modeli
new const g_NpcModel[] = "models/hostage.mdl";
//NPC Sayisi
new NpcSayisi;
//NPC Sesleri
new const g_NpcOlumSesi[][] = {
"barney/ba_die1.wav",
"barney/ba_die2.wav",
"barney/ba_die3.wav"
}
new const g_NpcHasarSesi[][] = {
"barney/ba_pain1.wav",
"barney/ba_pain2.wav",
"barney/ba_pain3.wav"
}
new const g_NpcKonusma[][] = {
"barney/dontaskme.wav",
"barney/haybuddy.wav",
"barney/hayfella.wav",
"barney/hellonicesuit.wav",
"barney/howyoudoing.wav"
}
public plugin_init()
{
register_plugin( PLUGIN, VERSION, AUTHOR );
//NPC Kontrol Menusu
register_clcmd( "say /npc", "NpcMenu" );
register_clcmd( "say_team /npc", "NpcMenu" );
//NPC Kontrol Fonksiyonlari
RegisterHam( Ham_TakeDamage, "info_target", "fw_NpcTakeDamage" ); //Hasar Fonksiyonu
RegisterHam( Ham_Killed, "info_target", "fw_NpcKilled" ); //Olum Fonksiyonu
RegisterHam( Ham_Think, "info_target", "fw_NpcThink" ); //Beyin Fonksiyonu
RegisterHam( Ham_TraceAttack, "info_target", "fw_NpcTraceAttack" ); //Mermi Fonksiyonu
RegisterHam( Ham_Touch, "info_target", "fw_NpcTouch" ); //Dokunma Fonksiyonu
}
public plugin_precache( )
{
npc_kan_spr = precache_model( "sprites/blood.spr" );
npc_kan_spr_sprey = precache_model( "sprites/bloodspray.spr" );
precache_model( g_NpcModel );
for( new i = 0 ; i < sizeof g_NpcOlumSesi ; i++)
precache_sound( g_NpcOlumSesi[ i ] );
for( new i = 0 ; i < sizeof g_NpcHasarSesi ; i++)
precache_sound( g_NpcHasarSesi[ i ] );
for( new i = 0 ; i < sizeof g_NpcKonusma ; i++)
precache_sound( g_NpcKonusma[ i ] );
}
public NpcMenu( id )
{
new iMenu[ 64 ];
formatex( iMenu, charsmax( iMenu ), "NPC - Oyuncu Olmayan Karakter" );
new menu = menu_create( iMenu, "NpcMenu_go" );
formatex( iMenu, charsmax( iMenu ), "\wNPC Olustur \y( Aim ile yer belirleyin )" );
menu_additem( menu, iMenu, "1" );
formatex( iMenu, charsmax( iMenu ), "\wNPC Kaldir \y( Aim ile secin )" );
menu_additem( menu, iMenu, "2" );
formatex( iMenu, charsmax( iMenu ), "\wButun NPC'leri Kaldir^n \y %d NPC Mevcut", NpcSayisi );
menu_additem( menu, iMenu, "3" );
menu_setprop( menu, MPROP_EXIT, MEXIT_ALL);
menu_setprop( menu, MPROP_EXITNAME, "\rCIKIS" );
menu_display(id, menu);
return PLUGIN_HANDLED;
}
public NpcMenu_go( id, menu, item )
{
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:
{
if( !is_user_alive( id ) ) return PLUGIN_HANDLED;
NpcOlustur( id );
}
case 2:
{
if( !is_user_alive( id ) ) return PLUGIN_HANDLED;
new iEnt, Vucut, NPC[ 64 ];
get_user_aiming( id, iEnt, Vucut );
if ( is_valid_ent( iEnt ) )
{
entity_get_string( iEnt, EV_SZ_classname, NPC, charsmax( NPC ) );
if ( equal( NPC, NpcClass ) )
{
remove_entity( iEnt );
NpcSayisi--;
client_print( id, print_chat, "[NPC] Bir NPC Kaldirildi." );
}
}
}
case 3:
{
remove_entity_name( NpcClass );
NpcSayisi = 0;
client_print( id, print_chat, "[NPC] Butun NPC'ler Kaldirildi." );
}
}
menu_destroy(menu);
return PLUGIN_HANDLED;
}
//NPC'ye dokundugumuzda bizmle konusacak ve hareket edecek.
public fw_NpcTouch( iEnt, id )
{
if( !is_user_alive( id ) )
return HAM_SUPERCEDE;
//Sadece 1 kere çalismasi için kontrol ediyoruz.
static Float: gametime, Float: Cooldown[ 32 ];
gametime = get_gametime();
if(gametime - 1.0 > Cooldown[ id ] )
{
//NPC kontrolu yapiyoruz. Burada NPC mizin ClassName yani ismini sorgulayarak onu baska nesnelerden ayiriyoruz.
//Sadece bizim NPC mizde calismasi icin kontrol ediyoruz. Duvara degdiginde konusmasini istemeyiz :)
new NPC[ 64 ];
entity_get_string( iEnt, EV_SZ_classname, NPC, charsmax( NPC ) );
if( equali( NPC, NpcClass ) )
{
//NPC'ye dokundugumuzda hareket edecek. Hareketleri g_NpcTalkAnimations degiskeninden aldik.
Util_PlayAnimation( iEnt, g_NpcTalkAnimations[ random( sizeof g_NpcTalkAnimations ) ] );
//NPC'ye dokunudugumuzda bizimle konusucak. Sesleri g_NpcKonusma degiskeninden aldik.
emit_sound( iEnt, CHAN_VOICE, g_NpcKonusma[ random( sizeof g_NpcKonusma ) ], VOL_NORM, ATTN_NORM, 0, PITCH_NORM );
}
Cooldown[ id ] = gametime;
}
return HAM_IGNORED;
}
//NPC'ye hasar verdigimizde hareket edecek ve bagiracak.
public fw_NpcTakeDamage( iEnt, inflictor, attacker, Float:damage, bits )
{
//NPC kontrolu yapiyoruz. Burada NPC mizin ClassName yani ismini sorgulayarak onu baska nesnelerden ayiriyoruz.
new NPC[ 64 ];
entity_get_string( iEnt, EV_SZ_classname, NPC, charsmax( NPC ) );
if( equali( NPC, NpcClass ) )
{
//NPC'ye hasar verdigimizde hareket edecek. Hareketleri g_NpcDamageAnimations degiskeninden aldik.
Util_PlayAnimation( iEnt, g_NpcDamageAnimations[ random( sizeof g_NpcDamageAnimations ) ], 1.25 );
//NPC'ye hasar verdigimizde bagiracak. Sesleri g_NpcHasarSesi degiskeninden aldik.
emit_sound( iEnt, CHAN_VOICE, g_NpcHasarSesi[ random( sizeof g_NpcHasarSesi ) ], VOL_NORM, ATTN_NORM, 0, PITCH_NORM );
}
}
//NPC'yi olduruyoruz.
public fw_NpcKilled( iEnt, Killer )
{
new NPC[ 64 ];
entity_get_string( iEnt, EV_SZ_classname, NPC, charsmax( NPC ) );
if( equali( NPC, NpcClass ) )
{
//g_NpcOldu degiskenini dogru tanimladik.
g_NpcOldu[ iEnt ] = true;
//NPC oldugunde olum animasyonu calisacak.
Util_PlayAnimation(iEnt, g_NpcDeathAnimations[ random( sizeof g_NpcDeathAnimations ) ] );
//Oldugunde NPC'nin içinden geçebiliriz. SOLID_NOT entity nin içinden geçilmesini kapatir.
entity_set_int( iEnt, EV_INT_solid, SOLID_NOT );
//NPC'yi olu olarak tanimladik.
entity_set_int( iEnt, EV_INT_deadflag, DEAD_DEAD );
//NPC'nin cesedinin hasar almasini kapattik.
entity_set_float(iEnt, EV_FL_takedamage, 0.0 );
//NPC oldugunde bagiracak.
emit_sound( iEnt, CHAN_VOICE, g_NpcOlumSesi[ random( sizeof g_NpcOlumSesi ) ], VOL_NORM, ATTN_NORM, 0, PITCH_NORM );
client_print( Killer, print_chat, "[NPC] NPC'yi oldurdunuz." );
//NPC oldugunden 5 saniye sonra cesedi yerden silinecek.
set_task( 5.0, "NpcOluyuKaldir", iEnt );
}
return HAM_SUPERCEDE;
}
//NPC'yi kaldir
public NpcOluyuKaldir( Npc )
{
remove_entity( Npc );
}
//NPC'nin dusunme fonksiyonu yani beyni. bu fonksiyon içine NPC mize ne yaptirmak istiyorsaniz ekleyebilirsiniz.
//Biz sadece durmasini istiyoruz bu yuzden NPC miz durmaktan baska bisey yapmayacak.
public fw_NpcThink( iEnt )
{
if( !is_valid_ent( iEnt ) )
return HAM_SUPERCEDE;
new NPC[ 64 ];
entity_get_string( iEnt, EV_SZ_classname, NPC, charsmax( NPC ) );
if( !equali( NPC, NpcClass ) )
return HAM_SUPERCEDE;
//Eger NPC'miz oluyse dusunme fonksiyonunu kapat.
if( g_NpcOldu[ iEnt ] )
return HAM_SUPERCEDE;
//NPC sadece duracak yani durus animasyonu.
Util_PlayAnimation(iEnt, g_NpcIdleAnimations[ random( sizeof g_NpcIdleAnimations ) ] );
//NPC'nin beyni her 5 saniyede bir çalisacak.
entity_set_float( iEnt, EV_FL_nextthink, get_gametime() + 5.0 );
return HAM_IGNORED;
}
//NPC hasar fonksiyonu2, fark, bu fonksiyonda hasarimizin yonunu belirleyebiliyoruz. Bir bu fonksiyonu-
//NPC hasar aldiginda vucudundan kan cikmasi icin kullanacagiz.
public fw_NpcTraceAttack(iEnt, attacker, Float: damage, Float: direction[3], trace, damageBits)
{
if( !is_valid_ent( iEnt ) )
return HAM_SUPERCEDE;
new NPC[ 64 ];
entity_get_string( iEnt, EV_SZ_classname, NPC, charsmax( NPC ) );
if( equali( NPC, NpcClass ) )
{
//NPC hasar alma kapaliysa kan cikmasin.
if( entity_get_float( iEnt, EV_FL_takedamage ) == 0.0 )
return HAM_SUPERCEDE;
//Merminin son carptigi yerin koordinatlarini buluyoruz.
new Float: end[ 3 ];
get_tr2( trace, TR_vecEndPos, end );
//Mermi NPC'nin neresine çarptiysa kan o bolgeden cikacak.
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( npc_kan_spr_sprey );
write_short( npc_kan_spr );
write_byte( 247 );
write_byte( random_num( 5, 15 ) );
message_end();
}
return HAM_IGNORED;
}
//NPC icin animasyon,hareket fonksiyonu.
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);
}
//Nisan alinan noktanin koordinatlarini bul.
stock get_user_hitpoint(id, Float:hOrigin[3]) {
if ( ! is_user_alive( id ))
return 0;
new Float:fOrigin[3], Float:fvAngle[3], Float:fvOffset[3], Float:fvOrigin[3], Float:feOrigin[3];
new Float:fTemp[3];
pev(id, pev_origin, fOrigin);
pev(id, pev_v_angle, fvAngle);
pev(id, pev_view_ofs, fvOffset);
xs_vec_add(fOrigin, fvOffset, fvOrigin);
engfunc(EngFunc_AngleVectors, fvAngle, feOrigin, fTemp, fTemp);
xs_vec_mul_scalar(feOrigin, 9999.9, feOrigin);
xs_vec_add(fvOrigin, feOrigin, feOrigin);
engfunc(EngFunc_TraceLine, fvOrigin, feOrigin, 0, id);
global_get(glb_trace_endpos, hOrigin);
return 1;
}
//ve NPC mizi bu fonksiyonda olusturuyoruz.
public NpcOlustur( id )
{
//NPC icin koordinat ve aci degiskenleri olusturduk.
new Float: Origin[ 3 ], Float: Angle[ 3 ];
//Herhangi bir entity yani nesne yaratiyoruz sonra bu nesneyi NPC olarak tanimlayacagiz.
new iEnt = create_entity( "info_target" );
//Yaptigimiz nesneyi bizim NPC miz olarak tanimladik.
entity_set_string( iEnt, EV_SZ_classname, NpcClass );
//Aim ile koordinatlari buluyoruz. NPC miz o koordinatlarda olucak.
get_user_hitpoint( id, Origin );
Origin[ 2 ] += 70.0;
entity_set_origin( iEnt, Origin );
//Oyuncunun bakis acisini aliyoruzki NPC de o acida olussun.
entity_get_vector(id, EV_VEC_angles, Angle );
Angle[ 0 ] = 0.0;
entity_set_vector( iEnt, EV_VEC_angles, Angle );
//NPC mizin modelini ayarliyoruz.
entity_set_model( iEnt, g_NpcModel );
//NPC miz hareketini ayarliyoruz. Yani ittirilebilir bir entity olacak.
entity_set_int(iEnt, EV_INT_movetype, MOVETYPE_PUSHSTEP );
//NPC miz içi dolu bir nesne olucak yani içinden geçemeyiz.
entity_set_int(iEnt, EV_INT_solid, SOLID_BBOX );
//NPC miz hasar alabilir.
entity_set_float( iEnt, EV_FL_takedamage, 1.0 );
//NPC'nin canini 500 yaptik.
entity_set_float( iEnt, EV_FL_health, 500.0 );
//Simdide NPC mizin buyuklugunu ayarliyoruz bu degerler min ve max olarak ayarlanir. 3 boyutlu olarak yani.
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);
//NPC kafasini kontrol edebilir.
entity_set_byte( iEnt, EV_BYTE_controller1, 125 );
//ve NPC mizi yere sabitliyoruz yanlis anlamayin yani havada duvarda vb. yerde olusabilir eger olusursa yere indirir
//bu kod.
drop_to_floor( iEnt );
//NPC mizin canli oldugunu tanimliyoruz.
g_NpcOldu[ iEnt ] = false;
//NPC sayisina +1 ekliyoruz.
NpcSayisi++;
//NPC nin beyni 1 saniye sonra calisacak.
entity_set_float( iEnt, EV_FL_nextthink, get_gametime() + 1.0 );
}
İşte NPC miz:
Evet biraz gelişmiş bir NPC oluşturduk. Bu eklentide ki NPC konuşabiliyor, hasar alabiliyor ve hareket edebiliyor ama sadece yerinde duruyor. Bir menü yardımıyla NPC oluşturabilir, onu silebilirsiniz. Bu arada menü kodu "say /npc" Daha sonra biraz daha geliştirebiliriz. Hareket eden, koşan bir NPC gibi.
Anlamadığınız yer olursa sorabilirsiniz. Eklentide hata, bug, sorun olursa veya daha mantıklı bir algoritma varsa beni uyarabilirsiniz.
Kolay gelsin.