[Tutorial] Зомби для вашего сервера без NPC для 0.3z
#1

Вот написал простенький код когда узнал что в 0.3z появится нужные для этого кэлбэки.
За основу был взят давно забытый скрипт где создавали зомбяка и тот летал за указанным ID

Плюсы:
- Не летают
- Не ходят под землей
- Идут к самому ближайшему игроку
- Если он в машине, то бьют машину
- Издают звуки (например удар по машине или звук поедания человека)
- Максимальное количество зомби без стримеров: 167
- Максимальное количество с стримером: 334
- Слотов не жрут

Минусы:
- Нет анимаций т.е. ходят без передвижения ног ( мб исправлю это потом).
- Работает только с 0.3z!

И так если прочли плюсы и минусы и всё же захотели таких кровожадных тварей себе на сервер,то вот и мануал:
Ко всем дефайнам:
PHP Code:
#define MAX_ZOMBIES 40// максимальное кол-во зомби 
Ко всем переменным (new):
PHP Code:
new zhealth[MAX_ZOMBIES];
new 
zombie[MAX_ZOMBIES][7];
new 
Float:Zspeed 5.5;
new 
ZTimerSpeed 500;
enum zombiParts
{
    
partModel,
Float:RelX,
Float:RelY,
Float:RelZ,
Float:RelrX,
Float:RelrY,
Float:RelrZ
}
new 
z11[6][zombiParts]=
{
    {
2905,-0.115479,-0.023924, -1.280131, -90.00000090.000000,0.000000}, // нога
    
{2906, -0.2189950.200928, -0.2531350.000000180.0000000.000000}, // рука
    
{2907, -0.032227, -0.045897, -0.544213270.0000000.0000000.000000}, // туловище
    
{29060.1879870.158448, -0.2657930.0000000.0000000.000000}, // рука
    
{29080.0000000.0000000.000000270.00000090.0000000.000000},//голова
    
{29050.101074, -0.012694, -1.288253270.00000090.0000000.000000// нога
};
new 
z21[6][zombiParts]=
{
    {
29050.005614, -0.110107, -1.280131, -90.00000090.00000090.000000},
    {
2906, -0.148926, -0.180663, -0.2531350.000000180.00000090.000000},
    {
29070.047852, -0.039061, -0.544213270.0000000.00000090.000000},
    {
2906, -0.1523430.171387, -0.2657930.0000000.00000090.000000},
    {
29080.0000000.0000000.000000270.00000090.00000090.000000},
    {
29050.0009770.090332, -1.288253270.00000090.00000090.000000}
};
new 
usedzombi[MAX_ZOMBIES];
new 
TimerAtaca=-1
Ну и форвард впихните куда нибудь в верх.
PHP Code:
forward ZombieAtaca(playerid); 
В OnGameModeInit, тут кстати я использую TSetTimer от Xemyl, это один единый таймер который уменьшает нагрузку на сервер и придает точность таймерам, такая система снизит нагрузку на сервер от этих зомби, подробнее читайте в его теме, она находится вот тут http://pawno-info.ru/threads/153560-a_timer
PHP Code:
if (TimerAtaca!=-1)
    {
        
TKillTimer(TimerAtaca);
    }
    
TimerAtaca=TSetTimer("ZombieAtaca",ZTimerSpeed,1); 
Идем дальше
Где нибудь с низу создаем паблик, это сам движок зомби.
PHP Code:
new Float:X8,Float:Y8,Float:Z8,proveren,rand2,rand3;
new 
Float:X8,Float:Y8,Float:Z8,proveren,rand2,rand3;
public 
ZombieAtaca()
{
    new 
playerid,Float:pX,Float:pY,Float:pZ,Float:angle;
    new 
Float:pX3,Float:pY3,Float:pZ3,Float:PEPE,Float:PIPO;
    for (new 
j=0;jgetmaxzombieid();j++)
    {
    
///    printf("зомби id %d проходит обработку",j);
        
if(usedzombi[j] != 1)continue;
        
playerid GetClosestPlay(zombie[j][4]);
        if(
playerid == INVALID_PLAYER_ID) continue;
        
pX3 X8,pY3 Y8,pZ3Z8;
        
//printf("зомби id %d прошел обработку",j);
           
GetPlayerPos(playerid,pX,pY,pZ);
        
GetObjectPos(zombie[j][4],X8,Y8,Z8);
        
angle 180.0-atan2(X8-pX,Y8-pY);
        
PEPE floatsin((angle*3.14159/180.0));
        
PIPO floatcos((angle*3.14159/180.0));
        
SetObjectRotzombie[j][4], z11[4][RelrX],z11[4][RelrY],angle );
        if ( (
floatabs(pX3-X8) + floatabs(pY3-Y8) + floatabs(pZ3-Z8) )<2.5)
        {
            if( 
!= proveren)
            {
                
rand2 random(4);
                
rand3 random(3);
                switch(
rand2)
                {
                case 
0:pX-=rand3;
                case 
1:pX+=rand3;
                case 
2:pY-=rand3;
                case 
3:pY+=rand3;
                }
            }
        }
        
proveren j;
        if(!
IsPlayerInAnyVehicle(playerid))
        {
            if ( (
floatabs(pX-X8) + floatabs(pY-Y8) + floatabs(pZ-Z8) )>2.8)
            {
                
MoveObject(zombie[j][4],pX+z11[4][RelX]*PIPO+PEPE*z21[4][RelX],pY+z11[4][RelY]*PIPO+PEPE*z21[4][RelY],pZ+z21[4][RelZ]+0.7,Zspeed);
            }
            else 
OnZombieGiveDamage(playerid,7);
            continue;
        }
        else
        {
            if ( (
floatabs(pX-X8) + floatabs(pY-Y8) + floatabs(pZ-Z8) )>5.0)
            {
                
MoveObject(zombie[j][4],pX+z11[4][RelX]*PIPO+PEPE*z21[4][RelX],pY+z11[4][RelY]*PIPO+PEPE*z21[4][RelY],pZ+z21[4][RelZ]+0.7,Zspeed);
            }
            else 
OnZombieGiveDamage(playerid,7);
        }
    }
    return 
1;

Теперь делаем систему попадания по человеку:
PHP Code:
OnZombieGiveDamage(playerid,Float:damage)
{
    new 
Float:pX,Float:pY,Float:pZ;
    
GetPlayerPos(playerid,pX,pY,pZ);
    if ( !
IsPlayerInAnyVehicle(playerid))
    {
           new 
Float:H;
        
GetPlayerHealth(playerid,H);
        if(
<= 0.0) return true;
        
SetPlayerHealthAC(playerid,H-damage);
        
//lasttouch[playerid] = 1;
        
return PlaySoundForPlayersInRange(1960230pX,pY,pZ);
    }
    else
    {
        new 
veh,Float:vehp;
        
veh GetPlayerVehicleID(playerid);
        
GetVehicleHealth(vehvehp);
        
SetVehicleHealth(vehvehp-damage);
        
PlaySoundForPlayersInRange(1940130pX,pY,pZ);
    }
    return 
true;

Теперь необходимые функции для движка:
PHP Code:
getmaxzombies()
{
    new 
x;
    for (new 
j=0;j<getmaxzombieid();j++)
    {
        if(
usedzombi[j] == 1)++;
    }
    return 
x;
}
getmaxzombieid()
{
    new 
= -1;
    for (new 
j=0;j<MAX_ZOMBIES;j++)
    {
        if(
usedzombi[j] == 1)=j;
        continue;
    }
    return 
x+1;

Так а теперь система нахождения ближайшего игрока, вот тут не большая развилка, всё дело в том что я этих зомби делал для своего РП сервера, т.е. вы понимайте что зомби по всюду не всем игрокам понравится и поэтому я у себя сделал ограничение где зомби можно быть.

Для тех кто хочет что-бы зомби были по всюду:
PHP Code:
GetClosestPlay(objectid)
{
    new 
Float:min_dis 99999.99,
Float:player_dis,
    
player INVALID_PLAYER_ID;
    new 
Float:object_xFloat:object_yFloat:object_zFloat:temp_z;
    
GetObjectPos(objectidobject_xobject_yobject_z);
    
MapAndreas_FindAverageZ(object_xobject_ytemp_z);
    if (
object_z temp_z 2.0 || object_z-temp_z)
    {
        
SetObjectPos(objectidobject_xobject_y, (object_z temp_z 2.0));
    }
    foreach (new 
playerid Player)
    {
        if (
GetPlayerState(playerid) == PLAYER_STATE_SPECTATING) continue;
        if (
GetPlayerInterior(playerid)) continue; 
        
player_dis GetPlayerDistanceFromPoint(playeridobject_xobject_yobject_z);
        if (
player_dis min_dis)
        {
            
min_dis player_dis;
            
player playerid;
        }
    }
    return 
player;

Для тех кто хочет что-бы были только в определенных местах:
PHP Code:
GetClosestPlay(objectid)
{
    new 
Float:min_dis 99999.99,
Float:player_dis,
    
player INVALID_PLAYER_ID;
    new 
Float:object_xFloat:object_yFloat:object_zFloat:temp_z;
    
GetObjectPos(objectidobject_xobject_yobject_z);
    
GetPointZPos(object_xobject_ytemp_z);
    if (
object_z temp_z 2.0 || object_z-temp_z)
    {
        
SetObjectPos(objectidobject_xobject_y, (object_z temp_z 2.0));
    }
    foreach (new 
playerid Player)
    {
        if (
GetPlayerState(playerid) == PLAYER_STATE_SPECTATING) continue;
        if (
GetPlayerInterior(playerid) || Isahitman(playerid)) continue; 
        if (!
ISAZOMBIESPAWN(playerid) && !zombiespawn2(playerid)) continue; 
        
player_dis GetPlayerDistanceFromPoint(playeridobject_xobject_yobject_z);
        if (
player_dis min_dis)
        {
            
min_dis player_dis;
            
player playerid;
        }
    }
    return 
player;

Теперь систему попадания по зомби:

PHP Code:
public OnPlayerWeaponShot(playeridweaponidhittypehitidFloat:fXFloat:fYFloat:fZ)
{
    if(
hittype == BULLET_HIT_TYPE_OBJECT)
    {
        new 
zombieid2 IsThisAZombie2(hitid);
        if(
zombieid2 != -1)
        {
            new 
damage;
            if(
weaponid 10) {damage random(50);}// по сути эти строки зря сделал, сам решайте оставлять ли
            
else {damage random(20);}
              if(
Headshot(zombieid2,hitid))
            {
                
damage 70;
                
GameTextForPlayer(playerid"~r~Headshot"10006);
            }
            
zhealth[zombieid2] -= damage;
            if(
zhealth[zombieid2] < 1)
            {
                for (new 
i=0;i<6;i++)
                {
                       
StopObject(zombie[zombieid2][i]);
                       
DestroyObject(zombie[zombieid2][i]);
                       
usedzombi[zombieid2] =0;
                   }
                   
SendClientMessage(playerid,COLOR_WHITE"Вы убили зомби! +500 вирт");
                   
PlayerInfo[playerid][pCash] += 500;// даём ему денег
            
}
        
//    format(string3[playerid],180,"Damage -%d",damage);
        //    GameTextForPlayer(playerid, string3[playerid], 1000, 1);
            
PlayerPlaySound(playerid64010.00.00.0);
        }
    }
    return 
true;

И так что мы имеем?
- Движок зомби
- Нахождение игрока
- Попадание по игроку и его машине
- Урон зомби
Не хватает лишь самого главного создания зомби!
Ну тут тоже не большой вопрос у меня возник: Создавать зомби на определенных спавнах после смерти пред идущего или же после убийства игрока, в таком случае пришлось бы каждый час проверять и если все зомби убиты создавать одного нового.

Пока не решил,но скину код создания зомби:
PHP Code:
createzombie(playerid// ориентация на место положение игрока и его Angle
{
    new 
Float:pX,Float:pY,Float:pZ,Float:Ang;
    
GetPlayerPos(playerid,pX,pY,pZ);
    
GetPlayerFacingAngle(playerid,Ang);
    
pX=pX+3.0*floatsin(-Ang,degrees);
    
pY=pY+3.0*floatcos(-Ang,degrees);
    
pZ=pZ+0.7;
    return 
CrearZombie(pX,pY,pZ,Ang+180.0);
}
CrearZombie(Float:pX,Float:pY,Float:pZ,Float:angle)
{
    if (
getmaxzombies() <MAX_ZOMBIES)
    {
        for (new 
j=0;j<MAX_ZOMBIES;j++)
        {
            if(
usedzombi[j] == 0)
            {
                
zhealth[j] = 100;
                
usedzombi[j] =1;
                new 
Float:PEPE floatsin((angle*3.14159/180.0));
                 new 
Float:PIPO floatcos((angle*3.14159/180.0));
                for (new 
i=0;i<6;i++)
                {
                    
zombie[j][i]=CreateObject(z11[i][partModel],pX+z11[i][RelX]*PIPO+PEPE*z21[i][RelX],pY+z11[i][RelY]*PIPO+PEPE*z21[i][RelY],pZ+z21[i][RelZ],z11[i][RelrX],z11[i][RelrY],angle);
                }
                
AttachObjectToObject(zombie[j][5],zombie[j][4],0.011.30.09000);
                
AttachObjectToObject(zombie[j][3],zombie[j][4],-0.1 ,0.25,0.15027090);
                
AttachObjectToObject(zombie[j][2],zombie[j][4],0.050.55, -0.03202700);
                
AttachObjectToObject(zombie[j][1],zombie[j][4],-0.150.25, -0.1909090);
                
AttachObjectToObject(zombie[j][0],zombie[j][4],01.30, -0.10000);
                break;
            }
        }
    }
    return 
1;

Ах да чуть не забыл, что-бы зомби не летали и не ходили под землей нам потребуется это
https://sampforum.blast.hk/showthread.php?tid=275492
Ну а код корректировки ходьбы зомби уже есть в верху.

Жду предложений и критики.
Кстати напишите как лучше всего создавать зомби.


---------- Post added at 12:29 ---------- Previous post was at 12:15 ----------

Ой забыл добавить
это тоже нужно:
PHP Code:
IsThisAZombie2(object)
{
   for (new 
j=0;jgetmaxzombieid();j++)
   {
           if(
usedzombi[j] != 1)continue;
           for (new 
i=0;i<6;i++)
           {
               if(
object == zombie[j][i]) return j;
        }
   }
   return -
1;
}
IsThisAZombie2(object)
{
   for (new 
j=0;jgetmaxzombieid();j++)
   {
           if(
usedzombi[j] != 1)continue;
           for (new 
i=0;i<6;i++)
           {
               if(
object == zombie[j][i]) return j;
        }
   }
   return -
1;
}
Headshot(zombieid,objectid)
{
 if(
objectid == zombie[zombieid][4]) return true;
 return 
false;

Автор Caypen
Версия: 0.2

Спасибо за корректировку функции GetClosestPlay: Stepashka
Reply
#2

Для новичков сойдёт.
-Не увидел решения если НПС движется из точки в точку Б а между ними обрыв.
-Любят сливаться в одного.
-Зомби всегда бежит за близжайшим игроком. Ннт разделения. 10 игроков заставят одного к ним подойти и пока НПС бегут за ним то будут их расстреливать.
-Объекты по мере приближения всегда поворачиваются и ложатся.
-Зачем всегда пересоздавать объекты?
[ame]www.youtube.com/watch?v=A8eYbfli5lk[/ame]
Reply
#3

Quote:

-Не увидел решения если НПС движется из точки в точку Б а между ними обрыв.

Я проверял, зомби тут же тпшит в низ обрыва, правда вот потом когда он подойдет к краю обрыва то его тпшнит на верх, в этом ест ьне большой баг, думаешь стоит исправить?

Quote:

-Любят сливаться в одного.

Я вроде сделал фикс этого:
Quote:

if ( (floatabs(pX3-X8) + floatabs(pY3-Y8) + floatabs(pZ3-Z8) )<2.5)
{
if( j != proveren)
{
rand2 = random(4);
rand3 = random(3);
switch(rand2)
{
case 0:pX-=rand3;
case 1:pX+=rand3;
case 2:pY-=rand3;
case 3:pY+=rand3;
}
}
}
proveren = j;

Эта часть за нее отвечает, есть предложения по улучшению антисливания?
Quote:

-Зомби всегда бежит за близжайшим игроком. Ннт разделения. 10 игроков заставят одного к ним подойти и пока НПС бегут за ним то будут их расстреливать.

Да ты прав,но разве зомби в фильмах себя так же не ведут? Или стоит сделать проверку на афк ли игрок и сколько зомби за ним гонются?
Quote:

-Объекты по мере приближения всегда поворачиваются и ложатся.

С твоими объектами может и да, у меня не какие не сиджеолени и они не переворачиваются.
Quote:

-Зачем всегда пересоздавать объекты?

Вся проблема в том что не существует функции SetObjectFacingAngle,поэтому приходится пересоздавать.
Кстати олени ржачные.
Reply
#4

Quote:

Вся проблема в том что не существует функции SetObjectFacingAngle

Зато есть SetObjectRot и GetObjectRot
Reply
#5

Да и на твоём видео олени ложатся только при убийстве.
Reply
#6

Чёт расписал совсем как для Pawno-Info
Reply
#7

Quote:

- Максимальное количество с стримером: 334

Смысл тогда вообще в таких зомби? 300 слотов не много, можно и плагином воспользоваться, по функциональней будет.
Reply
#8

Quote:
Originally Posted by KriD
View Post
Зато есть SetObjectRot и GetObjectRot
Хм и в правду сейчас попробую, + видео сделаю.
Reply
#9

Quote:
Originally Posted by XemyL
View Post
Смысл тогда вообще в таких зомби? 300 слотов не много, можно и плагином воспользоваться, по функциональней будет.
В этом вся проблема, нет не единого плагина для 0.3x R2 и для 0.3z

В прочем я могу переделать модельку зомби что-бы доступно было 1000 зомби.
Reply
#10

Может использовать этот MapAndreas плагин, обновлен и меньше жрет.
https://sampforum.blast.hk/showthread.php?tid=275492

Quote:
Originally Posted by KriD
View Post
Зато есть SetObjectRot и GetObjectRot
Без пересоздания некоторые части тела идут быстрее чем другие.
Reply
#11

Пока снимал видео нашел 4 бага, исправляю...
Reply
#12

Quote:
Originally Posted by Cypen
View Post
Без пересоздания некоторые части тела идут быстрее чем другие.
Двигай один объект, а остальные просто прикрепи к нему.
Reply
#13

Quote:
Originally Posted by Stepashka
View Post
Двигай один объект, а остальные просто прикрепи к нему.
И какой такой функцией я приатачу объект к объекту?
Reply
#14

Quote:
Originally Posted by Cypen
View Post
И какой такой функцией я приатачу объект к объекту?
AttachObjectToObject

PS Я рекомендую вам изучить базовый набор функций, их не так много, или вы не задержитесь в нашем общесте.
Reply
#15

Quote:

Здесь сидят люди которые не ленятся изучать то с чем работают и внимательно читать документацию, а те кто в упор не хотят этого делать обычно получают очень много негативных комментариев и просто предпочитают не оставаться тут.

Я пришел сюда с павно-инфо, мне надоело что там очень много рекламы и людей которые создают мануалы в которах пишут что stock быстрее чем public и этим вы ускорите свой мод на 250 процентов и сотня глупых вопросов, именно это меня начало там раздражать, вот и решил сюда прийти(пока-что только на 50 процентов), тут вроде такого нет.
Reply
#16

Ну давай учится.

pawn Code:
GetClosestPlay(objectid) {
    new Float:min_dis = 99999.99,
        Float:player_dis,
        player = INVALID_PLAYER_ID;
    new Float:object_x, Float:object_y, Float:object_z, Float:temp_z;
    GetObjectPos(objectid, object_x, object_y, object_z);
    MapAndreas_FindZ_For2DCoord(object_x, object_y, temp_z);
    if (object_z > temp_z + 2.0 || object_z < temp_z) {
        SetObjectPos(objectid, object_x, object_y, (object_z = temp_z + 2.0)));
    }
    foreach (new playerid : Player)
    {
        if (GetPlayerState(playerid) == PLAYER_STATE_SPECTATING) continue;
        if (GetPlayerInterior(playerid) || Isahitman(playerid)) continue; // Обрати внимание какой вид имеют стандартные функции!
        if (!ISAZOMBIESPAWN(playerid) && !zombiespawn2(playerid)) continue; // А где сами функции и почему имена у них разные? И предыдущий комментарий сюда применим.
        player_dis = GetPlayerDistanceFromPoint(playerid, object_x, object_y, object_z);
        if (player_dis < min_dis) {
            min_dis = player_dis;
            player = playerid;
        }
    }
    return player;
}
И запомни на будущее, всегда сперва начинай с проверок которые делаются быстрей, например сравнение двух переменных, внутренние функции, а уж потом самописные. Это к о проверке игроков!

И ни когда не используй однобуквенные переменные!
Reply
#17

Пара вопросов:
1. Почему не использовать однобуквенные переменные?
2. if (GetPlayerInterior(playerid)) Тут разве не проверка на равен ли GetPlayerInterior(playerid) одному?
Reply
#18

Про ISAZOMBIESPAWN(playerid)
Я писал в мануале пусть люди сами себе сделают такие функции, т.к. у всех разные координаты будут и не всех устроят мои.
Reply
#19

Quote:
Originally Posted by Cypen
View Post
Да ты прав,но разве зомби в фильмах себя так же не ведут? Или стоит сделать проверку на афк ли игрок и сколько зомби за ним гонются?
Можно же отойти от фильмов, у тебя игра, тебе нужно заставлять игроков играть против зомби а не сидеть как в тире. Тем более это во много раз усложнит игру, игрок будет более бдительным, напряжённым и в процессе игры.
Reply
#20

Quote:
Originally Posted by Cypen
View Post
Пара вопросов:
1. Почему не использовать однобуквенные переменные?
2. if (GetPlayerInterior(playerid)) Тут разве не проверка на равен ли GetPlayerInterior(playerid) одному?
Потому что ты в них запутаешься, и они плохо читаются.
Нет тут проверка что GetPlayerInterior(playerid) отличен от нуля.
Все что отлично от null, false, 0 или "" интерпретируется как истина.
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)