Город Мастеров
IPB

Здравствуйте, гость ( Вход | Регистрация )

 Правила этого форума ПРАВИЛА РАЗДЕЛА
 
Ответить в эту темуОткрыть новую тему
> WalkWaypoints
denis0k
сообщение Apr 7 2008, 12:29
Сообщение #1


Level 19
Иконки Групп

Класс: Воин
Характер: Lawful Good
Раса: Человек
NWN: Скриптинг [PW]
Gem of the North
Край Лесов



У нас очень обширно используются посты и маршруты, решил это дело проверить профайлером. Ужаснулся - в первые минуты скрипт срабатывает 70к раз (IMG:style_emoticons/kolobok_light/wacko.gif) Точнее сразу 1.6к и дальше растет. Начал копать скрипты - там скажем так писец:
Neverwinter Script
X0_I0_WALKWAY:
void WalkWayPoints(int nRun = FALSE, float fPause = 1.0)
{
    ...
    // Лечение рекурсии что называется серпом по яйцам - сначала 55 раз запустимся,
    // сделаем проверки, а потом выйдем, ибо нафик не надо было запускаться
    if (bIsFighting == TRUE || bIsInConversation == TRUE || bMoving == TRUE || bWaiting == TRUE)
        return;
    ...
    object oWay = GetNextWalkWayPoint(OBJECT_SELF);
    if (GetIsObjectValid(oWay) == TRUE)
    {
        ...
        // Даже если непись стоит на точке, действие в стек добавится.
        // Не знаю, как влияет на производительность, но лучше проверить расстояние до точки.
        ActionMoveToObject(oWay, nRun);
        if(GetLocalInt(oWay,"X2_L_WAYPOINT_SETFACING") == 1)
        {
            // Аналогично
            ActionDoCommand(SetFacing(GetFacing(oWay)));
        }
        // А вот и корень зла (IMG:style_emoticons/kolobok_light/smile.gif) Рекурсия с шагом 1 сек на всех неписях с точками. Сама функция еще
        // запускается из хертбита. Получается ужасный хаос с кучей ненужных срабатываний,
        // которые хоть и отрезаются в начале, но ресурсы кушают неслабо
        ActionWait(fPause);
        ActionDoCommand(WalkWayPoints(nRun,fPause));
        ...
    }
    ...
}

У всех по-разному конечно получится с цифрами, зависит от кол-во неписей с точками, но самыми банальными проверками (описанные тут + проверка в хб на присутствие игрока вблизи) и отключением рекурсии мне удалось снизить кол-во запусков раз в 100 кажется (IMG:style_emoticons/kolobok_light/smile.gif) Причем цифра перестала расти со временем в геометрической прогрессии. Минус - неписи чуть тормозят - после прерывания возобновляют ходьбу не сразу, а через 1-6 секунд (запуск только в хб остался).
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
gennady
сообщение Apr 8 2008, 06:56
Сообщение #2


Level 9
Иконки Групп

Класс: Обыватель
Характер: Lawful Good
Раса: Человек
NWN: Модмейкер
Рыцарская Сага



Цитата(denis0k @ Apr 7 2008, 13:29) *
У нас очень обширно используются посты и маршруты, решил это дело проверить профайлером. Ужаснулся - в первые минуты скрипт срабатывает 70к раз Точнее сразу 1.6к и дальше растет. Начал копать скрипты - там скажем так писец:

У нас тоже стал тормозить модуль от ХБ с этой «левой» функцией WalkWayPoints. Это произошло от большого объема модуля и НПС с точками ходьбы. Отключение ХБ, когда нет в локе героя привело к потере ориентировки НПС и он стал бродить не по маршруту… К тому же базовая атака НПС глюченная и не пашет с ХБ… Пришлось полностью переписать функцию WalkWayPoints, и оставить ее так же только на ХБ скрипте. В инклюд вошло всего три функции: ходьба по точкам, посты (дневные и ночные), атака НПС.
P.S. если кому интересно могу выложить скрипты… (IMG:style_emoticons/kolobok_light/wink3.gif)

Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Sugo77
сообщение May 10 2008, 12:10
Сообщение #3


Level 3
*

Класс: Монах
Характер: Lawful Good
Раса: Эльф



Выложи если нетрудно,с пояснениями где на что заменять.

Сообщение отредактировал Sugo77 - May 10 2008, 12:11
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
gennady
сообщение May 10 2008, 15:58
Сообщение #4


Level 9
Иконки Групп

Класс: Обыватель
Характер: Lawful Good
Раса: Человек
NWN: Модмейкер
Рыцарская Сага



ОК!
Для полной замены базового WalkWayPoints, нужно сделать:
1. Меняем скрипт прерывания и окончания диалога nw_walk_wp
2. Переписываем скрипт спавна nw_c2_default9
3. Переписываем скрипт OnPerception монстров NW_C2_DEFAULT2
4. Пишем новый скрипт для ХБ монстров nw_c2_default1
5. Ну и сама новая функция ходьбы в инклюде gg_walkway

Перенастройка модуля никакая не потребуется… НПС ходят по стандартным точкам ходьбы сделанным ранее редактором. Единственное отличие точки поста, я заменил на свои: Тег НПС+_POST

Стоит т.ж. учитывать локалку на НПС "WPOIN_GO", если нужно для сценок и быстрого старта функции ходьбы, то ее нужно обнулять… Но это не критично, т.к. когда герой покинет область НПС, то автоматом обнулится и эта локалка. Вот и все (IMG:style_emoticons/kolobok_light/smile.gif)

скрипт прерывания и окончания диалога nw_walk_wp
Neverwinter Script
//:://////////////////////////////////////////////////
//:: Created By: Gennady  nw_walk_wp
//:://////////////////////////////////////////////////
void main()
{
    SetLocalInt(GetFirstPC(), "ConversationState", 0);
    SetLocalInt(OBJECT_SELF,"WPOIN_GO",0);
    SetCutsceneMode(GetFirstPC(), FALSE);
    SetImmortal(GetFirstPC(), FALSE);
    SetPlotFlag(GetFirstPC(), FALSE);
}

скрипт спавна nw_c2_default9 Тут пробита выдача золота и зелья. но это уж дело вкуса, сами пишите кому чего нужно…
Neverwinter Script
//:://////////////////////////////////////////////////
//:: Created By: Gennady  nw_c2_default9
//:://////////////////////////////////////////////////

// Дать золото
// object oTarget - Кому даем
// int nMnGold - множитель *(случайность от 1 до 10)
void CreateGold(object oTarget, int nMnGold);
// Дать зелье
// object oTarget - Кому даем
void CreateZel(object oTarget);

////////////////////////////////////////////////////////////////////////////////
//________________ Дать золото _________________________________________________
void CreateGold(object oTarget, int nMnGold)
{
int nGold = Random(10)+1; nGold = nMnGold*nGold;
CreateItemOnObject("nw_it_gold001", oTarget, nGold);
}
//_________ Дать зелье __________
void CreateZel(object oTarget)
{
int nRandom = Random(32) + 1;
string sItem;
switch (nRandom)
{
case 1: sItem = "nw_it_mpotion022"; break;
case 2: sItem = "nw_it_mpotion023"; break;
case 3: sItem = "nw_it_mpotion021"; break;
case 4: sItem = "nw_it_mpotion001"; break;
case 5: sItem = "nw_it_mpotion020"; break;
case 6: sItem = "nw_it_medkit001"; break;
case 7: sItem = "nw_it_medkit002"; break;
case 8: sItem = "nw_it_mpotion009"; break;
case 9: sItem = "nw_it_mpotion010"; break;
case 10: sItem = "nw_it_mpotion013"; break;
case 11: sItem = "nw_it_mpotion014"; break;
case 12: sItem = "nw_it_mpotion019"; break;
case 13: sItem = "nw_it_mpotion005"; break;
case 14: sItem = "nw_it_mpotion020"; break;
case 15: sItem = "nw_it_mpotion022"; break;
case 16: sItem = "nw_it_mpotion023"; break;
case 17: sItem = "nw_it_mpotion021"; break;
case 18: sItem = "nw_it_mpotion001"; break;
case 19: sItem = "nw_it_mpotion020"; break;
case 20: sItem = "nw_it_medkit001"; break;
case 21: sItem = "nw_it_medkit002"; break;
case 22: sItem = "nw_it_mpotion009"; break;
case 23: sItem = "nw_it_mpotion003"; break;
case 24: sItem = "nw_it_mpotion002"; break;
case 25: sItem = "nw_it_mpotion011"; break;
case 26: sItem = "nw_it_mpotion018"; break;
case 27: sItem = "nw_it_mpotion016"; break;
case 28: sItem = "nw_it_mpotion006"; break;
case 29: sItem = "nw_it_mpotion015"; break;
case 30: sItem = "nw_it_mpotion004"; break;
case 31: sItem = "nw_it_mpotion017"; break;
case 32: sItem = "nw_it_mpotion007"; break;
}
CreateItemOnObject(sItem, oTarget, 1);
}
////////////////////////////////////////////////////////////////////////////////
void main()
{
object oSelf = OBJECT_SELF ;
int nRaType = GetRacialType(oSelf);

if(nRaType == RACIAL_TYPE_UNDEAD || nRaType == RACIAL_TYPE_ANIMAL ||
    nRaType == RACIAL_TYPE_VERMIN) return; // Нежить, животное, паразит.
if(GetLevelByClass(CLASS_TYPE_COMMONER, oSelf) >= 1) // Простолюдин
CreateGold(oSelf, 10);
if (d10() > 5) return;
if(d10() > 7) CreateZel(oSelf);
if(d10() > 5) CreateGold(oSelf, 3);
}

скрипт OnPerception монстров NW_C2_DEFAULT2
Neverwinter Script
//:://////////////////////////////////////////////////
//:: NW_C2_DEFAULT2
/*
  Default OnPerception event handler for NPCs.
  Handles behavior when perceiving a creature for the
  first time.
*/

//:://////////////////////////////////////////////////
//:: Created By: Gennady
//:: Created On: 3.11.2006
#include "nw_i0_generic"

void main()
{
// * if not runnning normal or better Ai then exit for performance reasons
    // * if not runnning normal or better Ai then exit for performance reasons
    if (GetAILevel() == AI_LEVEL_VERY_LOW) return;

    object oPercep = GetLastPerceived();
    int bSeen = GetLastPerceptionSeen();

    // This will cause the NPC to speak their one-liner
    // conversation on perception even if they are already
    // in combat.
    if(GetSpawnInCondition(NW_FLAG_SPECIAL_COMBAT_CONVER
SATION)
       && GetIsPC(oPercep)
       && bSeen)
    {
        SpeakOneLinerConversation();
    }

    // March 5 2003 Brent
    // Had to add this section back in, since  modifications were not taking this specific
    // example into account -- it made invisibility basically useless.
    //If the last perception event was hearing based or if someone vanished then go to search mode
    if ((GetLastPerceptionVanished()) && GetIsEnemy(GetLastPerceived()))
    {
        object oGone = GetLastPerceived();
        if((GetAttemptedAttackTarget() == GetLastPerceived() ||
           GetAttemptedSpellTarget() == GetLastPerceived() ||
           GetAttackTarget() == GetLastPerceived()) && GetArea(GetLastPerceived()) != GetArea(OBJECT_SELF))
        {
            //SpeakString("dude...like disappeared.");
           ClearAllActions();
           DetermineCombatRound();
        }
    }

    // This section has been heavily revised while keeping the
    // pre-existing behavior:
    // - If we're in combat, keep fighting.
    // - If not and we've perceived an enemy, start to fight.
    //   Even if the perception event was a 'vanish', that's
    //   still what we do anyway, since that will keep us
    //   fighting any visible targets.
    // - If we're not in combat and haven't perceived an enemy,
    //   see if the perception target is a PC and if we should
    //   speak our attention-getting one-liner.
    if (GetIsFighting(OBJECT_SELF)) {
        // don't do anything else, we're busy
        MyPrintString("GetIsFighting: TRUE");

    }
    // * BK FEB 2003 Only fight if you can see them. DO NOT RELY ON HEARING FOR ENEMY DETECTION
    else if (GetIsEnemy(oPercep) && bSeen) {
        MyPrintString("GetIsEnemy: TRUE");
        // We spotted an enemy and we're not already fighting
        if(!GetHasEffect(EFFECT_TYPE_SLEEP)) {
            if(GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) {
                MyPrintString("DetermineSpecialBehavior");
                DetermineSpecialBehavior();
            } else {
                MyPrintString("DetermineCombatRound");
                SetFacingPoint(GetPosition(oPercep));
                SpeakString("NW_I_WAS_ATTACKED", TALKVOLUME_SILENT_TALK);
                DetermineCombatRound();
            }
        }
    } else {
        if (bSeen) {
            MyPrintString("GetLastPerceptionSeen: TRUE");
            if(GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) {
                DetermineSpecialBehavior();
            } else if (GetSpawnInCondition(NW_FLAG_SPECIAL_CONVERSATION)
                       && GetIsPC(oPercep))
            {
                // The NPC will speak their one-liner conversation
                // This should probably be:
                // SpeakOneLinerConversation(oPercep);
                // instead, but leaving it as is for now.
                ActionStartConversation(OBJECT_SELF);
            }
        }

        // activate ambient animations or walk waypoints if appropriate
       if (!IsInConversation(OBJECT_SELF))
       {
           if (GetIsPC(oPercep) &&
               (GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS)
                || GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVI
AN)
                || GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMA
TIONS)
                || GetIsEncounterCreature()))
           {
                SetAnimationCondition(NW_ANIM_FLAG_IS_ACTIVE);
           }
        }
    }

    // Send the user-defined event if appropriate
    if(GetSpawnInCondition(NW_FLAG_PERCIEVE_EVENT) && GetLastPerceptionSeen())
    {
        SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_PERCEIVE));
    }
}

скрипт ХБ монстров nw_c2_default1
Neverwinter Script
//:://////////////////////////////////////////////////
//:: Created By: Gennady  nw_c2_default1
//:://////////////////////////////////////////////////
#include "gg_walkway"
void main()
{
object oSelf = OBJECT_SELF;
if(GetArea(GetFirstPC()) != GetArea(oSelf)) // если ПС нет в локе
{
  AssignCommand(oSelf, ClearAllActions(TRUE));
  SetLocalInt(oSelf,"WPOIN_GO",0);
  return;
}
if (GetIsInCombat(oSelf)) {SetLocalInt(oSelf,"WPOIN_GO",0); return;}
if (IsInConversation(oSelf)) {SetLocalInt(oSelf,"WPOIN_GO",0); return;}
WayPOST(); //ДЛЯ ПОСТОВОГО
WalkWayPoints(); // ДЛЯ ХОДЬБЫ ПО ТОЧКАМ
ActAttackNPC(); // Атака врага
if (GetLocalInt(oSelf, "FLAG_HEARTBEAT") == 1)
SignalEvent(oSelf, EventUserDefined(EVENT_HEARTBEAT));
}

инклюда ходьбы gg_walkway
Neverwinter Script
//:://////////////////////////////////////////////////
//:: #include "gg_walkway"
//:: Created By: Gennady
//:: Created On: 3.11.2006
//:://////////////////////////////////////////////////

// Атака врага, если герой в радиусе 15 метров
void ActAttackNPC(object oSelf = OBJECT_SELF);
//ДЛЯ ПОСТОВОГО
// Вернет на точку поста, повернет в сторону вектора точки
// Точка поста равна тэгу ПС +"_POST"
// Должна быть более 2 метров от ближайшей точки ходьбы
// Если интеллект выше 20, и есть точки ходьбы - ночью ходит, днем пост
void WayPOST(object oSelf = OBJECT_SELF);
// ДЛЯ ХОДЬБЫ ПО ТОЧКАМ  расположенным в этой области
void WalkWayPoints(object oSelf = OBJECT_SELF);
/////////////////////////////////////////////////////////////////////////////

// Атака врага, если герой в радиусе 15 метров  /////////////////////////////
void ActAttackNPC(object oSelf = OBJECT_SELF)
{
object oVrag = GetFirstObjectInShape(SHAPE_SPHERE, 15.0, GetLocation(oSelf), TRUE, OBJECT_TYPE_CREATURE);
if (GetDistanceBetween(GetFirstPC(), oSelf) < 15.0)
{
  while (GetIsObjectValid(oVrag))// Проверить враждебного ПС в радиусе 15 метров
  {
   if (GetObjectSeen(oVrag, oSelf) && GetIsEnemy(oVrag, oSelf))
    {
     AssignCommand(oSelf, ClearAllActions(TRUE));
     AssignCommand(oSelf, ActionAttack(oVrag));
     return;
    }
   oVrag = GetNextObjectInShape(SHAPE_SPHERE, 15.0, GetLocation(oSelf), TRUE, OBJECT_TYPE_CREATURE);
  }
}
}
///////////////   ДЛЯ ПОСТОВОГО   //////////////////////////////////////////
void WayPOST(object oSelf = OBJECT_SELF)
{
object oWayPOST = GetNearestObjectByTag(GetTag(oSelf)+"_POST");
if (GetIsObjectValid(oWayPOST))
{
   if (GetAbilityScore(oSelf, ABILITY_INTELLIGENCE) > 20)
   {
    if (GetIsNight())
    {
     if (GetDistanceBetween(oWayPOST, oSelf) < 1.0)
     SetLocalInt(oSelf,"WPOIN_GO",0);
     WalkWayPoints(oSelf); return;
    }
    else
    SetLocalInt(oSelf,"WPOIN_GO",1);
   }
   float fFacing = GetFacing(oWayPOST);
   ClearAllActions();
   ActionForceMoveToObject(oWayPOST, FALSE, 0.0, 30.0);
   ActionDoCommand(DelayCommand(0.3, SetFacing(fFacing)));
}
}
// ДЛЯ ХОДЬБЫ ПО ТОЧКАМ  расположенным в этой области  //////////////////////
void WalkWayPoints(object oSelf = OBJECT_SELF)
{
if (GetLocalInt(oSelf, "WPOIN_GO") == 1) return;
object oWay = GetNearestObjectByTag("WP_"+GetTag(oSelf)+"_01");
int i =1;
int iNPoint;
string sPoint;

if (GetIsObjectValid(oWay))
{
  ClearAllActions();
  SetLocalInt(oSelf,"WPOIN_GO",1);
}
else  return;
  oWay = GetNearestObject(OBJECT_TYPE_WAYPOINT, oSelf,i);
  while (GetIsObjectValid(oWay))// Цикл определить ближайшую точку
  {
   i++;
   string sTag = GetTag(oWay);
   // Тэг точки без 3 последних букв
   string sTreb = GetStringLeft(sTag, GetStringLength(sTag)-3);
   if("WP_"+GetTag(oSelf) == sTreb)
    {
     iNPoint = StringToInt(GetStringRight(sTag, 2));
     if (iNPoint == 0)
     iNPoint = StringToInt(GetStringRight(sTag, 1));
     break ;
    }
    oWay = GetNearestObject(OBJECT_TYPE_WAYPOINT, oSelf,i);
  }
     if (iNPoint < 10) sPoint = "0" + IntToString(iNPoint);
     else  sPoint = IntToString(iNPoint);
     // Определили ближайшую точку
     oWay = GetNearestObjectByTag("WP_"+GetTag(oSelf)+"_"+sPoint);

while (GetIsObjectValid(oWay)) // Цикл на возрастание точек
{
   ActionForceMoveToObject(oWay, FALSE, 0.0, 30.0);
   iNPoint++;
   if (iNPoint < 10) sPoint = "0" + IntToString(iNPoint);
   else  sPoint = IntToString(iNPoint);
   oWay = GetNearestObjectByTag("WP_"+GetTag(oSelf)+"_"+sPoint);
}
   iNPoint = iNPoint-1;
   if (iNPoint < 10) sPoint = "0" + IntToString(iNPoint);
   else  sPoint = IntToString(iNPoint);
oWay = GetNearestObjectByTag("WP_"+GetTag(oSelf)+"_"+sPoint);
while (GetIsObjectValid(oWay))  // Цикл на убывание точек
{
   ActionForceMoveToObject(oWay, FALSE, 0.0, 30.0);
   iNPoint--;
   if (iNPoint < 10) sPoint = "0" + IntToString(iNPoint);
   else sPoint = IntToString(iNPoint);
   oWay = GetNearestObjectByTag("WP_"+GetTag(oSelf)+"_"+sPoint);
}
ActionDoCommand(SetLocalInt(oSelf,"WPOIN_GO",0));
}

P.S. Скрипты все проверены и работают уже в моем моде 2 года, нареканий у меня к ним пока нет… (IMG:style_emoticons/kolobok_light/biggrin.gif)

Сообщение отредактировал gennady - May 10 2008, 16:00
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Sugo77
сообщение May 10 2008, 20:02
Сообщение #5


Level 3
*

Класс: Монах
Характер: Lawful Good
Раса: Эльф



О Боже лучше я повременю с такими глобальными переменами в модуле.
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
gennady
сообщение May 11 2008, 06:32
Сообщение #6


Level 9
Иконки Групп

Класс: Обыватель
Характер: Lawful Good
Раса: Человек
NWN: Модмейкер
Рыцарская Сага



Не боись! Вернуть все в исходное положение будет просто! Достаточно выкинуть эти 5 скриптов из модуля и это вернет модуль к базовым скриптам.
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
denis0k
сообщение May 20 2008, 09:33
Сообщение #7


Level 19
Иконки Групп

Класс: Воин
Характер: Lawful Good
Раса: Человек
NWN: Скриптинг [PW]
Gem of the North
Край Лесов



Ну думаю следует заметить 2 вещи:
1) это чисто сингловый набор, причем даже при прохождении мода по сетке скрипт будет работать не так, как ожидается
2) в стандартных скриптах на спавн происходит инициализация и дальше непись ходит по уже известным точкам в строгой последовательности. Этот же вариант каждый раз после сброса берет ближайшую точку, ведет к ней и потом номер увеличивает. В принципе это в глаза не бросается, но косяк есть, даже два. Во-первых, после диалога непись может делать пару шагов назад (если точки стоят далеко друг от друга, то может и не пару), а потом идти вперед. Во-вторых, происходит сброс направления. Т.е. непись прошел все точки по возрастанию, по убыванию половину, с ним поговорили, и он опять пойдет по возрастанию.
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
gennady
сообщение May 20 2008, 12:53
Сообщение #8


Level 9
Иконки Групп

Класс: Обыватель
Характер: Lawful Good
Раса: Человек
NWN: Модмейкер
Рыцарская Сага



Цитата
1) это чисто сингловый набор

И я этого не скрывал! (IMG:style_emoticons/kolobok_light/smile.gif) Хотя достаточно в скрипте ХБ пробить героя (т.е. заменить GetFirstPC()) на то что нужно для шарда… Остальное все пробито на OBJECT_SELF.
Цитата
2) но косяк есть, даже два. Во-первых, после диалога непись может делать пару шагов назад (если точки стоят далеко друг от друга, то может и не пару), а потом идти вперед. Во-вторых, происходит сброс направления.

Я бы сказал, что это не косяки, а БОЛЬШИЕ ПЛЮСЫ!
НПС и базовой функции может вернуться назад, а потом двигать вперед, все зависит от фазы прерывания. А с направлением движения, после прерывания, в базовом варианте вообще большие косяки… НПС движется к точке, хоть и соответствующей его былому движению, но +1. И если маршрут ломанный, и к тому же блокируется объектами, НПС может просто на полминуты воткнуться в стену, или пойти по совсем ему не свойственной траектории… Это что лучше?

Я же просто хочу еще отметить пару нюансов по своей функции.
1. Обязательно должна быть первая точка маршрута.
2. Желательно не ставить рядом начальную и конечную точку маршрута. Иначе НПС может пойти сперва по убывающим точкам...
3. НПС движется только по точкам своей области.
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
ReZkiy
сообщение Sep 11 2011, 19:56
Сообщение #9


Level 5
**

Класс: Вор
Характер: Neutral Good
Раса: Человек



Цитата(gennady @ May 10 2008, 18:58) *
ОК!
Для полной замены базового WalkWayPoints, нужно сделать:
1. Меняем скрипт прерывания и окончания диалога nw_walk_wp
2. Переписываем скрипт спавна nw_c2_default9
3. Переписываем скрипт OnPerception монстров NW_C2_DEFAULT2
4. Пишем новый скрипт для ХБ монстров nw_c2_default1
5. Ну и сама новая функция ходьбы в инклюде gg_walkway

Перенастройка модуля никакая не потребуется… НПС ходят по стандартным точкам ходьбы сделанным ранее редактором. Единственное отличие точки поста, я заменил на свои: Тег НПС+_POST

Стоит т.ж. учитывать локалку на НПС "WPOIN_GO", если нужно для сценок и быстрого старта функции ходьбы, то ее нужно обнулять… Но это не критично, т.к. когда герой покинет область НПС, то автоматом обнулится и эта локалка. Вот и все (IMG:style_emoticons/kolobok_light/smile.gif)

скрипт прерывания и окончания диалога nw_walk_wp
Neverwinter Script
//:://////////////////////////////////////////////////
//:: Created By: Gennady  nw_walk_wp
//:://////////////////////////////////////////////////
void main()
{
    SetLocalInt(GetFirstPC(), "ConversationState", 0);
    SetLocalInt(OBJECT_SELF,"WPOIN_GO",0);
    SetCutsceneMode(GetFirstPC(), FALSE);
    SetImmortal(GetFirstPC(), FALSE);
    SetPlotFlag(GetFirstPC(), FALSE);
}

скрипт спавна nw_c2_default9 Тут пробита выдача золота и зелья. но это уж дело вкуса, сами пишите кому чего нужно…
Neverwinter Script
//:://////////////////////////////////////////////////
//:: Created By: Gennady  nw_c2_default9
//:://////////////////////////////////////////////////

// Дать золото
// object oTarget - Кому даем
// int nMnGold - множитель *(случайность от 1 до 10)
void CreateGold(object oTarget, int nMnGold);
// Дать зелье
// object oTarget - Кому даем
void CreateZel(object oTarget);

////////////////////////////////////////////////////////////////////////////////
//________________ Дать золото _________________________________________________
void CreateGold(object oTarget, int nMnGold)
{
int nGold = Random(10)+1; nGold = nMnGold*nGold;
CreateItemOnObject("nw_it_gold001", oTarget, nGold);
}
//_________ Дать зелье __________
void CreateZel(object oTarget)
{
int nRandom = Random(32) + 1;
string sItem;
switch (nRandom)
{
case 1: sItem = "nw_it_mpotion022"; break;
case 2: sItem = "nw_it_mpotion023"; break;
case 3: sItem = "nw_it_mpotion021"; break;
case 4: sItem = "nw_it_mpotion001"; break;
case 5: sItem = "nw_it_mpotion020"; break;
case 6: sItem = "nw_it_medkit001"; break;
case 7: sItem = "nw_it_medkit002"; break;
case 8: sItem = "nw_it_mpotion009"; break;
case 9: sItem = "nw_it_mpotion010"; break;
case 10: sItem = "nw_it_mpotion013"; break;
case 11: sItem = "nw_it_mpotion014"; break;
case 12: sItem = "nw_it_mpotion019"; break;
case 13: sItem = "nw_it_mpotion005"; break;
case 14: sItem = "nw_it_mpotion020"; break;
case 15: sItem = "nw_it_mpotion022"; break;
case 16: sItem = "nw_it_mpotion023"; break;
case 17: sItem = "nw_it_mpotion021"; break;
case 18: sItem = "nw_it_mpotion001"; break;
case 19: sItem = "nw_it_mpotion020"; break;
case 20: sItem = "nw_it_medkit001"; break;
case 21: sItem = "nw_it_medkit002"; break;
case 22: sItem = "nw_it_mpotion009"; break;
case 23: sItem = "nw_it_mpotion003"; break;
case 24: sItem = "nw_it_mpotion002"; break;
case 25: sItem = "nw_it_mpotion011"; break;
case 26: sItem = "nw_it_mpotion018"; break;
case 27: sItem = "nw_it_mpotion016"; break;
case 28: sItem = "nw_it_mpotion006"; break;
case 29: sItem = "nw_it_mpotion015"; break;
case 30: sItem = "nw_it_mpotion004"; break;
case 31: sItem = "nw_it_mpotion017"; break;
case 32: sItem = "nw_it_mpotion007"; break;
}
CreateItemOnObject(sItem, oTarget, 1);
}
////////////////////////////////////////////////////////////////////////////////
void main()
{
object oSelf = OBJECT_SELF ;
int nRaType = GetRacialType(oSelf);

if(nRaType == RACIAL_TYPE_UNDEAD || nRaType == RACIAL_TYPE_ANIMAL ||
    nRaType == RACIAL_TYPE_VERMIN) return; // Нежить, животное, паразит.
if(GetLevelByClass(CLASS_TYPE_COMMONER, oSelf) >= 1) // Простолюдин
CreateGold(oSelf, 10);
if (d10() > 5) return;
if(d10() > 7) CreateZel(oSelf);
if(d10() > 5) CreateGold(oSelf, 3);
}

скрипт OnPerception монстров NW_C2_DEFAULT2
Neverwinter Script
//:://////////////////////////////////////////////////
//:: NW_C2_DEFAULT2
/*
  Default OnPerception event handler for NPCs.
  Handles behavior when perceiving a creature for the
  first time.
*/

//:://////////////////////////////////////////////////
//:: Created By: Gennady
//:: Created On: 3.11.2006
#include "nw_i0_generic"

void main()
{
// * if not runnning normal or better Ai then exit for performance reasons
    // * if not runnning normal or better Ai then exit for performance reasons
    if (GetAILevel() == AI_LEVEL_VERY_LOW) return;

    object oPercep = GetLastPerceived();
    int bSeen = GetLastPerceptionSeen();

    // This will cause the NPC to speak their one-liner
    // conversation on perception even if they are already
    // in combat.
    if(GetSpawnInCondition(NW_FLAG_SPECIAL_COMBAT_CONVER
SATION)
       && GetIsPC(oPercep)
       && bSeen)
    {
        SpeakOneLinerConversation();
    }

    // March 5 2003 Brent
    // Had to add this section back in, since  modifications were not taking this specific
    // example into account -- it made invisibility basically useless.
    //If the last perception event was hearing based or if someone vanished then go to search mode
    if ((GetLastPerceptionVanished()) && GetIsEnemy(GetLastPerceived()))
    {
        object oGone = GetLastPerceived();
        if((GetAttemptedAttackTarget() == GetLastPerceived() ||
           GetAttemptedSpellTarget() == GetLastPerceived() ||
           GetAttackTarget() == GetLastPerceived()) && GetArea(GetLastPerceived()) != GetArea(OBJECT_SELF))
        {
            //SpeakString("dude...like disappeared.");
           ClearAllActions();
           DetermineCombatRound();
        }
    }

    // This section has been heavily revised while keeping the
    // pre-existing behavior:
    // - If we're in combat, keep fighting.
    // - If not and we've perceived an enemy, start to fight.
    //   Even if the perception event was a 'vanish', that's
    //   still what we do anyway, since that will keep us
    //   fighting any visible targets.
    // - If we're not in combat and haven't perceived an enemy,
    //   see if the perception target is a PC and if we should
    //   speak our attention-getting one-liner.
    if (GetIsFighting(OBJECT_SELF)) {
        // don't do anything else, we're busy
        MyPrintString("GetIsFighting: TRUE");

    }
    // * BK FEB 2003 Only fight if you can see them. DO NOT RELY ON HEARING FOR ENEMY DETECTION
    else if (GetIsEnemy(oPercep) && bSeen) {
        MyPrintString("GetIsEnemy: TRUE");
        // We spotted an enemy and we're not already fighting
        if(!GetHasEffect(EFFECT_TYPE_SLEEP)) {
            if(GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) {
                MyPrintString("DetermineSpecialBehavior");
                DetermineSpecialBehavior();
            } else {
                MyPrintString("DetermineCombatRound");
                SetFacingPoint(GetPosition(oPercep));
                SpeakString("NW_I_WAS_ATTACKED", TALKVOLUME_SILENT_TALK);
                DetermineCombatRound();
            }
        }
    } else {
        if (bSeen) {
            MyPrintString("GetLastPerceptionSeen: TRUE");
            if(GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) {
                DetermineSpecialBehavior();
            } else if (GetSpawnInCondition(NW_FLAG_SPECIAL_CONVERSATION)
                       && GetIsPC(oPercep))
            {
                // The NPC will speak their one-liner conversation
                // This should probably be:
                // SpeakOneLinerConversation(oPercep);
                // instead, but leaving it as is for now.
                ActionStartConversation(OBJECT_SELF);
            }
        }

        // activate ambient animations or walk waypoints if appropriate
       if (!IsInConversation(OBJECT_SELF))
       {
           if (GetIsPC(oPercep) &&
               (GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS)
                || GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVI
AN)
                || GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMA
TIONS)
                || GetIsEncounterCreature()))
           {
                SetAnimationCondition(NW_ANIM_FLAG_IS_ACTIVE);
           }
        }
    }

    // Send the user-defined event if appropriate
    if(GetSpawnInCondition(NW_FLAG_PERCIEVE_EVENT) && GetLastPerceptionSeen())
    {
        SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_PERCEIVE));
    }
}

скрипт ХБ монстров nw_c2_default1
Neverwinter Script
//:://////////////////////////////////////////////////
//:: Created By: Gennady  nw_c2_default1
//:://////////////////////////////////////////////////
#include "gg_walkway"
void main()
{
object oSelf = OBJECT_SELF;
if(GetArea(GetFirstPC()) != GetArea(oSelf)) // если ПС нет в локе
{
  AssignCommand(oSelf, ClearAllActions(TRUE));
  SetLocalInt(oSelf,"WPOIN_GO",0);
  return;
}
if (GetIsInCombat(oSelf)) {SetLocalInt(oSelf,"WPOIN_GO",0); return;}
if (IsInConversation(oSelf)) {SetLocalInt(oSelf,"WPOIN_GO",0); return;}
WayPOST(); //ДЛЯ ПОСТОВОГО
WalkWayPoints(); // ДЛЯ ХОДЬБЫ ПО ТОЧКАМ
ActAttackNPC(); // Атака врага
if (GetLocalInt(oSelf, "FLAG_HEARTBEAT") == 1)
SignalEvent(oSelf, EventUserDefined(EVENT_HEARTBEAT));
}

инклюда ходьбы gg_walkway
Neverwinter Script
//:://////////////////////////////////////////////////
//:: #include "gg_walkway"
//:: Created By: Gennady
//:: Created On: 3.11.2006
//:://////////////////////////////////////////////////

// Атака врага, если герой в радиусе 15 метров
void ActAttackNPC(object oSelf = OBJECT_SELF);
//ДЛЯ ПОСТОВОГО
// Вернет на точку поста, повернет в сторону вектора точки
// Точка поста равна тэгу ПС +"_POST"
// Должна быть более 2 метров от ближайшей точки ходьбы
// Если интеллект выше 20, и есть точки ходьбы - ночью ходит, днем пост
void WayPOST(object oSelf = OBJECT_SELF);
// ДЛЯ ХОДЬБЫ ПО ТОЧКАМ  расположенным в этой области
void WalkWayPoints(object oSelf = OBJECT_SELF);
/////////////////////////////////////////////////////////////////////////////

// Атака врага, если герой в радиусе 15 метров  /////////////////////////////
void ActAttackNPC(object oSelf = OBJECT_SELF)
{
object oVrag = GetFirstObjectInShape(SHAPE_SPHERE, 15.0, GetLocation(oSelf), TRUE, OBJECT_TYPE_CREATURE);
if (GetDistanceBetween(GetFirstPC(), oSelf) < 15.0)
{
  while (GetIsObjectValid(oVrag))// Проверить враждебного ПС в радиусе 15 метров
  {
   if (GetObjectSeen(oVrag, oSelf) && GetIsEnemy(oVrag, oSelf))
    {
     AssignCommand(oSelf, ClearAllActions(TRUE));
     AssignCommand(oSelf, ActionAttack(oVrag));
     return;
    }
   oVrag = GetNextObjectInShape(SHAPE_SPHERE, 15.0, GetLocation(oSelf), TRUE, OBJECT_TYPE_CREATURE);
  }
}
}
///////////////   ДЛЯ ПОСТОВОГО   //////////////////////////////////////////
void WayPOST(object oSelf = OBJECT_SELF)
{
object oWayPOST = GetNearestObjectByTag(GetTag(oSelf)+"_POST");
if (GetIsObjectValid(oWayPOST))
{
   if (GetAbilityScore(oSelf, ABILITY_INTELLIGENCE) > 20)
   {
    if (GetIsNight())
    {
     if (GetDistanceBetween(oWayPOST, oSelf) < 1.0)
     SetLocalInt(oSelf,"WPOIN_GO",0);
     WalkWayPoints(oSelf); return;
    }
    else
    SetLocalInt(oSelf,"WPOIN_GO",1);
   }
   float fFacing = GetFacing(oWayPOST);
   ClearAllActions();
   ActionForceMoveToObject(oWayPOST, FALSE, 0.0, 30.0);
   ActionDoCommand(DelayCommand(0.3, SetFacing(fFacing)));
}
}
// ДЛЯ ХОДЬБЫ ПО ТОЧКАМ  расположенным в этой области  //////////////////////
void WalkWayPoints(object oSelf = OBJECT_SELF)
{
if (GetLocalInt(oSelf, "WPOIN_GO") == 1) return;
object oWay = GetNearestObjectByTag("WP_"+GetTag(oSelf)+"_01");
int i =1;
int iNPoint;
string sPoint;

if (GetIsObjectValid(oWay))
{
  ClearAllActions();
  SetLocalInt(oSelf,"WPOIN_GO",1);
}
else  return;
  oWay = GetNearestObject(OBJECT_TYPE_WAYPOINT, oSelf,i);
  while (GetIsObjectValid(oWay))// Цикл определить ближайшую точку
  {
   i++;
   string sTag = GetTag(oWay);
   // Тэг точки без 3 последних букв
   string sTreb = GetStringLeft(sTag, GetStringLength(sTag)-3);
   if("WP_"+GetTag(oSelf) == sTreb)
    {
     iNPoint = StringToInt(GetStringRight(sTag, 2));
     if (iNPoint == 0)
     iNPoint = StringToInt(GetStringRight(sTag, 1));
     break ;
    }
    oWay = GetNearestObject(OBJECT_TYPE_WAYPOINT, oSelf,i);
  }
     if (iNPoint < 10) sPoint = "0" + IntToString(iNPoint);
     else  sPoint = IntToString(iNPoint);
     // Определили ближайшую точку
     oWay = GetNearestObjectByTag("WP_"+GetTag(oSelf)+"_"+sPoint);

while (GetIsObjectValid(oWay)) // Цикл на возрастание точек
{
   ActionForceMoveToObject(oWay, FALSE, 0.0, 30.0);
   iNPoint++;
   if (iNPoint < 10) sPoint = "0" + IntToString(iNPoint);
   else  sPoint = IntToString(iNPoint);
   oWay = GetNearestObjectByTag("WP_"+GetTag(oSelf)+"_"+sPoint);
}
   iNPoint = iNPoint-1;
   if (iNPoint < 10) sPoint = "0" + IntToString(iNPoint);
   else  sPoint = IntToString(iNPoint);
oWay = GetNearestObjectByTag("WP_"+GetTag(oSelf)+"_"+sPoint);
while (GetIsObjectValid(oWay))  // Цикл на убывание точек
{
   ActionForceMoveToObject(oWay, FALSE, 0.0, 30.0);
   iNPoint--;
   if (iNPoint < 10) sPoint = "0" + IntToString(iNPoint);
   else sPoint = IntToString(iNPoint);
   oWay = GetNearestObjectByTag("WP_"+GetTag(oSelf)+"_"+sPoint);
}
ActionDoCommand(SetLocalInt(oSelf,"WPOIN_GO",0));
}

P.S. Скрипты все проверены и работают уже в моем моде 2 года, нареканий у меня к ним пока нет… (IMG:style_emoticons/kolobok_light/biggrin.gif)

Он говорит "Нет главной функции" в инклюде gg_walkway
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Ilerien
сообщение Sep 11 2011, 20:06
Сообщение #10


Level 11
Иконки Групп

Класс: Волшебник
Характер: Lawful Evil
Раса: Эльф
NWN: Скриптинг [PW]
Gem of the North



Странно было бы, если бы она там была (IMG:style_emoticons/kolobok_light/rolleyes.gif)
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Talarasha
сообщение Sep 13 2011, 14:19
Сообщение #11


Level 6
**

Класс: Маг
Характер: Lawful Evil
Раса: Нежить



Цитата
Он говорит "Нет главной функции" в инклюде gg_walkway

Скрипты в НВНе собираются либо как действия, либо как условия. В первом случае в них должна присутствовать ф-я main() (та самая "главная функция), во втором случаей StartingConditional(), иначе они не скомпилируются. Функционал инклюдов пишется в файлы скриптов, из которых эти инклюды вызываются. Сам файл инклюда не компилируется, поэтому на эту ошибку можно внимания не обращать. Некоторые скриптеры по заданной программистами Биоваров манере еще оставляют в конце файла закомментированный main() - это удобно, чтобы проверять работоспособность функций инклюда прямо на месте, надо просто раскомментировать ее во время работы над кодом, а на конечном этапе, когда все готово - закомментировать обратно.
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения

Ответить в эту темуОткрыть новую тему
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



Текстовая версия Сейчас: 28th March 2024 - 21:26