Zplague
Gostaria de reagir a esta mensagem? Crie uma conta em poucos cliques ou inicie sessão para continuar.

Zplague Entrar

Seu portal de Zombie Plague no Brasil


description[Tutorial] Criando um NPC  Empty[Tutorial] Criando um NPC

more_horiz
Vendo que há um grande número de postos de trabalho na linha de Twilight Suzuka Como: Faça um NPC perfeito . . Decidi tentar e fazer o meu próprio NPC usando esse tutorial, mas acrescentou recursos extras
Algumas delas são:
Bata animações
Animações de morte
Animações ociosas
Sangrar / desencadear efeitos
Voz NPC falando
E muito mais!

Antes de iniciar este tutorial vamos explicar melhor o que é exatamente um NPC e por que devemos fazer antes de um how. NPC significa caráter não-jogável. Como o nome sugere, é simplesmente uma entidade que não é jogável. . Nós, como programadores têm total controle sobre a forma como eles interagem e trabalham Alguns exemplos do que um NPC pode fazer são:


Espectadores que anima. (Muito legal para fazer para o futebol Jam)
Um proprietário de loja de itens
Props para o seu mod. (Fazendo lâmpada / luz mensagens que poderiam flicker)
Tudo o que você pode pensar!

Tudo bem! Permite, finalmente, começar a fazer o nosso próprio NPC! Começamos incluindo as bibliotecas necessárias para tornar o nosso NPC

Código PHP:

Código:

# Include < amxmodx >
# include < amxmisc >
# include < fakemeta >
# include < engine >
# include < hamsandwich >  
Um grupo de variáveis ​​globais que nosso NPC irá usar.

Código PHP:

Código:

//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];  
Agora temos que precache nosso modelo e os sons ou o jogo vai cair! E também um comando para gerar o nosso NPC.

Nesta seção, temos de iniciar algumas encaminha para o nosso NPC. Trata-se de onde os recursos extras são chamados de.

Este também é o lugar onde nós podemos carregar nossas configurações salvas.

PHP Code:

Código:

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[i]);
    for(i = 0 ; i < sizeof g_NpcSoundDeath ; i++)
        precache_sound(g_NpcSoundDeath[i]);

    precache_model(g_NpcModel)
}

public plugin_cfg()
{
    Load_Npc()
}  
Quando digitar "/ NPC" um menu será exibido com as opções do que fazer.
Nota: Eu estou usando o novo sistema de menu AMXX para exibir o menu, graças a EMP `

PHP Code:

Código:

public ClCmd_NPC(id)
{
    //Create a new menu
    new menu = menu_create("NPC: Main Menu", "Menu_Handler");
    
    //Add some items to the newly created menu
    menu_additem(menu, "Create NPC", "1");
    menu_additem(menu, "Delete NPC", "2");
    menu_additem(menu, "Save current NPC locations", "3");
    menu_additem(menu, "Delete all 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] NPC origin saved succesfully");
        }
        case 4:
        {
            //Remove all NPCs from the map
            remove_entity_name(g_NpcClassName);
            
            client_print(id, print_chat, "[AMXX] ALL NPC origin removed");
        }
    }
    
    //Keep the menu displayed when we choose an option
    menu_display(id, menu);
    
    return PLUGIN_HANDLED;
}  
Adicionar alguns recursos extras para o nosso NPC.

PHP Code:

Código:

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)
}

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, "Hello");
            }
            
            //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
}  
Em caso de um novo ciclo. Vamos redefinir nossas propriedades NPC.

PHP Code:

Código:

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);
    }
}  
O método que realmente cria o nosso NPC.

PHP Code:

Código:

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)
Os métodos que carregar e salvar os locais do nosso NPC.

PHP Code:

Código:

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.
    }
    
}  
Diversos método para a criação de animações para o nosso NPC.

PHP Code:

Código:

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);
}  
Pronto voce criou Seu Npc

Clique Aqui Para Baixar Sma Pronta


Creditos : Mini_Midget

description[Tutorial] Criando um NPC  EmptyRe: [Tutorial] Criando um NPC

more_horiz
Zplague12 

description[Tutorial] Criando um NPC  EmptyRe: [Tutorial] Criando um NPC

more_horiz
Seria bom dar uma comentada nos códigos para quem não sabe entender o que faz cada linha.

description[Tutorial] Criando um NPC  EmptyRe: [Tutorial] Criando um NPC

more_horiz
privacy_tip Permissões neste sub-fórum
Não podes responder a tópicos
power_settings_newInicie sessão para responder