• Уважаемые гости и новички, приветствуем Вас на нашем форуме
    Здесь вы можете найти ответы практически на все свои вопросы о серии игр «Готика» (в том числе различных модах на нее), «Ведьмак», «Ризен», «Древние свитки», «Эра дракона» и о многих других играх. Можете также узнать свежие новости о разработке новых проектов, восхититься творчеством наших форумчан, либо самим показать, что вы умеете. Ну и наконец, можете обсудить общие увлечения или просто весело пообщаться с посетителями «Таверны».

    Чтобы получить возможность писать на форуме, оставьте сообщение в этой теме.
    Удачи!

Вопросы по скриптингу

MaGoth

★★★★★★★★★★★
Администратор
Регистрация
7 Янв 2003
Сообщения
19.367
Благодарности
7.815
Баллы
995
  • Первое сообщение
  • #1
Прежде чем задавать вопросы, ознакомьтесь с документацией..
1) Читать онлайн
2) Архив с офлайн-версией(chm) во вложении
 

Вложения

  • Vam_tutor.rar
    171,6 KB · Просмотры: 573
Последнее редактирование модератором:

Xeдин


Модостроитель
Регистрация
3 Дек 2008
Сообщения
1.448
Благодарности
1.976
Баллы
365
Ага, я тоже в Одиссее попробовал, вроде встает, только влево и вправо двигается.

1670255476167.png

Пост автоматически объединён:

Фиг знает, что ты там задумал)
Он просто не хотел давать возможность взламывать если ловкости меньше чем кол-во поворотов нужных для взлома, деленное на 10. Я ему просетил эту переменную что бы он мог в скриптах видеть длину последовательности взлома. )
 
Последнее редактирование:

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
вопрос в том как на скриптах корректно прервать взаимодействие с сундуком и встать.

Привожу фрагмент кода из мод-фикса, из функции, в которой происходит "исследование" сундука, запертого на ключ. Функция вызывается в момент попытки взаимодействия с сундуком. В исходном положении ГГ стоит перед сундуком, взяв его в фокус.
Daedalus:
ScreenMessage = "Нужен подходящий ключ."; // Формирование строки для вывода на экран.
hero.aivar[AIV_TALKBEFOREATTACK] = 56; // Изменение переменной. Служит для вывода надписи на экран по завершению взаимодействия с сундуком с помощью циклической функции.

AI_UseMob(hero,"CHESTBIG",0); // ГГ начинает принудительно взаимодействовать с сундуком. Опускается перед ним на колено.
AI_Wait(hero,0.5); // Пауза.
AI_PlayAni(hero,"T_CHESTBIG_S0_NEEDKEY"); // Проигрывание специальной анимации ковыряния в замке.
AI_PlayAni(hero,"T_CHESTBIG_S0_2_STAND"); // Проигрывание анимации вставания от сундука. Видимое прекращение взаимодействия.
AI_UseMob(hero,"CHESTBIG",-1); // Формальное прекращение взаимодействия с сундуком. По окончании на экран выводится надпись.
AI_PlayAni(hero,"T_DONTKNOW"); // Проигрывание анимации пожимания плечами.
AI_OutputSVM(hero,hero,"$NEEDKEY"); // Произнесение комментария "Для этого мне нужен ключ."
AI_Wait(hero,0.2); // Пауза.

Этот фрагмент относится к взаимодействию с "большими сундуками", для которых используется блок анимаций CHESTBIG. В Г1 ещё есть малые сундуки, для которых используется блок анимаций CHESTSMALL. Для них предусмотрен другой фрагмент кода. Не помню, есть ли малые сундуки в Г2. Если есть, и изменять игровой мир не хочется, можно прописать определение типа сундука в скриптах. Вот фрагмент кода из функции B_AssessUseMob, в которой анализируется факт взаимодействия кого-то (other) с объектом.

Daedalus:
var string detectedMob; // Переменная для запоминания вида объекта. Тип переменной - строка.

detectedMob = Npc_GetDetectedMob(other); // Определяется тип объекта, который находится в фокусе персонажа other. При взаимодействии объект находится в фокусе.

if(Hlp_StrCmp(detectedMob,"CHESTBIG") || Hlp_StrCmp(detectedMob,"CHESTSMALL")) // Проверка в условии, является ли объект сундуком (малым ИЛИ большим).
 
Последнее редактирование:

Xeдин


Модостроитель
Регистрация
3 Дек 2008
Сообщения
1.448
Благодарности
1.976
Баллы
365
KirTheSeeker, можешь попробовать как я написал сделать, только через gameloop. Тогда ГГ даже садится не будет, просто надпись выведется что низя.

Daedalus:
var int UnionPickLockStrNum;
func event GameLoop(){
     if(UnionPickLockStrNum > 0){
      var int DEX_Lock_KTS_1;
      DEX_Lock_KTS_1 = hero.attribute[ATR_DEXTERITY] / 10;
      if(UnionPickLockStrNum >= DEX_Lock_KTS_1){
            Print("Нужно больше ловкости.");
            AI_StandUpQuick(hero);
      };
     };
};
 

WoOliN

Участник форума
Регистрация
13 Окт 2012
Сообщения
347
Благодарности
196
Баллы
210
del.
 
Последнее редактирование:

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.001
Благодарности
969
Баллы
295
ElderGamer, спасибо. очень познавательно :-=)

KirTheSeeker,

Daedalus:
func void G_PickLock(var int bSuccess,var int bBrokenOpen)
{
    var int rnd;
    var int DEX_Lock_KTS_1   ;
    DEX_Lock_KTS_1 = hero.attribute[ATR_DEXTERITY] / 10;
    
    if(UnionPickLockStrNum >= DEX_Lock_KTS_1)
    {
        Print("Нужно больше ловкости.");
AI_PlayAni(hero,"T_CHESTBIG_S0_2_STAND"); // Проигрывание анимации вставания от сундука. Видимое прекращение взаимодействия.
AI_UseMob(hero,"CHESTBIG",-1); // Формальное прекращение взаимодействия с сундуком. По окончании на экран выводится надпись.
AI_PlayAni(hero,"T_DONTKNOW"); // Проигрывание анимации пожимания плечами.
AI_OutputSVM(hero,hero,"$NEEDKEY"); // Произнесение комментария "Для этого мне нужен ключ."
AI_Wait(hero,0.2); // Пауза.
//        B_Say_Overlay(self,self,"$MISSINGITEM");
    };
...
Пост автоматически объединён:

можешь попробовать как я написал сделать, только через gameloop. Тогда ГГ даже садится не будет, просто надпись выведется что низя.
он вроде изначально хотел что бы герой садился ковырялся в замке , а потом "понимал" что у него мало ловкости :)
 

Xeдин


Модостроитель
Регистрация
3 Дек 2008
Сообщения
1.448
Благодарности
1.976
Баллы
365
он вроде изначально хотел что бы герой садился ковырялся в замке , а потом "понимал" что у него мало ловкости
Если приседать, вспомнил что похожее есть еще в Одиссее, посмотрел как там и адаптировал немного, получилось вот так. Вроде работает, но не знаю насколько на уровне скриптов это правильно.

Daedalus:
var int UnionPickLockStrNum;

func event GameLoop(){
     if(UnionPickLockStrNum > 0){
       var int DEX_Lock_KTS_1;
      DEX_Lock_KTS_1 = hero.attribute[ATR_DEXTERITY] / 10;
      if(UnionPickLockStrNum >= DEX_Lock_KTS_1){
          Print("Нужно больше ловкости.");
          AI_GotoFP(hero, "PICKLOCK");
          AI_AlignToFP(hero);
          AI_PlayAni(hero,"T_CHESTBIG_S0_UNLOCK");
          AI_StandUp (hero);
      };
     };
};
 
Последнее редактирование:

Oxbow

Участник форума
Регистрация
22 Дек 2017
Сообщения
265
Благодарности
33
Баллы
200
Только не смейтесь это я попытался создать зелье временного повышения атрибутов (используя зацикленный триггер), как думаете это будет работать?
Daedalus:
const int timer = 0;

func void B_CYCLE_FUNCTION()
{
if(hero.attribute[ATR_HITPOINTS_MAX] == 0) //Проверка, загружен ли ГГ в мир игры.
{
Wld_SendTrigger("CYCLE_TRIGGER"); //Вызов триггера c именем CYCLE_TRIGGER для зацикливания всей функции.
return; //Выход из функции.
};

timer += 1;

If (WolfSoul_Used == TRUE && (timer == WolfSoul_Used_Begin + 1200))
{
    B_RaiseAttribute(self,ATR_STRENGTH,-STR_WolfSoul);
    B_RaiseAttribute(self,ATR_DEXTERITY,-DEX_WolfSoul);
    WolfSoul_Used = FALSE;
};

Wld_SendTrigger("CYCLE_TRIGGER"); //Вызов триггера c именем CYCLE_TRIGGER для зацикливания всей функции.
};

Daedalus:
instance ItPo_WND_WolfSoul(C_Item)
{
    name = NAME_Trank;
    mainflag = ITEM_KAT_POTIONS;
    flags = ITEM_MULTI;
    value = Value_Speed;
    visual = "ItPo_Speed.3ds";
    material = MAT_GLAS;
    on_state[0] = UseItPo_WND_WolfSoul;
    scemeName = "POTIONFAST";
    wear = WEAR_EFFECT;
    effect = "SPELLFX_ITEMGLIMMER";
    description = "Снадобье духа волка";
    text[1] = "Временно повышает силу и ловкость на 9 единиц.";
    text[3] = NAME_Duration;
    count[3] = Time_Speed / 60000;
    text[5] = NAME_Value;
    count[5] = value;
};


func void UseItPo_WND_WolfSoul()
{
    B_RaiseAttribute(self,ATR_STRENGTH,STR_WolfSoul);
    B_RaiseAttribute(self,ATR_DEXTERITY,DEX_WolfSoul);
    WolfSoul_Used = TRUE;
    WolfSoul_Used_Begin = timer;
};

Daedalus:
var int WolfSoul_Used;
var int WolfSoul_Used_Begin;
const int STR_WolfSoul = 9;
const int DEX_WolfSoul = 9;
 

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.001
Благодарности
969
Баллы
295
Oxbow, ради интереса попробовал сделать триггер на юнион. получилось просто, понятно и быстро.

Daedalus:
//*************************************************************************//
//      функция запуска триггера
//*************************************************************************//
func void Start_Trigger_Attribute_TimeBonus(var c_npc slf,var int attribute,var int value,var int time)
{
    Attribute_TimeBonus = attribute;
    var C_Trigger trigger;
    //*************************************************************************//
    //- Func   - функция, которую будет вызывать триггер.
    //- Self   - NPC, который при вызове функции будет помещаться в self.
    //- Other  - NPC, который при вызове функции будет помещаться в other.
    //- Victim - NPC, который при вызове функции будет помещаться в victim.
    //AI_StartTriggerScriptEx(имя функции, задержка, self, other, victim) - расширенная функция, если необходимо указать в нее определенных участников
    trigger = AI_StartTriggerScriptEx("Trigger_Attribute_TimeBonus", 1, slf, null, null);
     trigger.AIVariables[0] = time;        // число повторов(секунд) триггера
    trigger.AIVariables[1] = attribute;  // атрибут
     trigger.AIVariables[2] = value;      // бонус к атрибуту
 
};

//*************************************************************************//
//      сам Trigger
//*************************************************************************//

func int Trigger_Attribute_TimeBonus()
{

    if (SelfTrigger.Delay < 1000)
    {
        SelfTrigger.Delay = 1000; // раз в секунду
        B_RaiseAttribute(self,SelfTrigger.AIVariables[1],SelfTrigger.AIVariables[2]);
    };

    Hlp_msg = Str_Format("Trigger_Attribute_TimeBonus[%s]. Счётчик %i", self.name, SelfTrigger.AIVariables[0]);
    Hlp_PrintConsole(Hlp_msg);

    SelfTrigger.AIVariables[0] -= 1;        // счётчик времени
 
    if (SelfTrigger.AIVariables[0] <= 0)
    {
        B_RaiseAttribute(self,SelfTrigger.AIVariables[1], -SelfTrigger.AIVariables[2]);
        attribute_TimeBonus = 0;
        return LOOP_END;
    };

    return LOOP_CONTINUE;
};

собрал проект. добавил функцию которая меняет атрибуты, инстанции зелий. тестировал на НВ. архив с проектом прилагаю.
 

Вложения

  • !_Trigger_Attribute_TimeBonus.zip
    3,4 KB · Просмотры: 9
Последнее редактирование:

Oxbow

Участник форума
Регистрация
22 Дек 2017
Сообщения
265
Благодарности
33
Баллы
200
Oxbow, ради интереса попробовал сделать триггер на юнион. получилось просто, понятно и быстро.

Daedalus:
//*************************************************************************//
//      функция запуска триггера
//*************************************************************************//
func void Start_Trigger_Attribute_TimeBonus(var c_npc slf,var int attribute,var int value,var int time)
{
    Attribute_TimeBonus = attribute;
    var C_Trigger trigger;
    //*************************************************************************//
    //- Func   - функция, которую будет вызывать триггер.
    //- Self   - NPC, который при вызове функции будет помещаться в self.
    //- Other  - NPC, который при вызове функции будет помещаться в other.
    //- Victim - NPC, который при вызове функции будет помещаться в victim.
    //AI_StartTriggerScriptEx(имя функции, задержка, self, other, victim) - расширенная функция, если необходимо указать в нее определенных участников
    trigger = AI_StartTriggerScriptEx("Trigger_Attribute_TimeBonus", 1, slf, null, null);
     trigger.AIVariables[0] = time;        // число повторов(секунд) триггера
    trigger.AIVariables[1] = attribute;  // атрибут
     trigger.AIVariables[2] = value;      // бонус к атрибуту
 
};

//*************************************************************************//
//      сам Trigger
//*************************************************************************//

func int Trigger_Attribute_TimeBonus()
{

    if (SelfTrigger.Delay < 1000)
    {
        SelfTrigger.Delay = 1000; // раз в секунду
        B_RaiseAttribute(self,SelfTrigger.AIVariables[1],SelfTrigger.AIVariables[2]);
    };

    Hlp_msg = Str_Format("Trigger_Attribute_TimeBonus[%s]. Счётчик %i", self.name, SelfTrigger.AIVariables[0]);
    Hlp_PrintConsole(Hlp_msg);

    SelfTrigger.AIVariables[0] -= 1;        // счётчик времени
 
    if (SelfTrigger.AIVariables[0] <= 0)
    {
        B_RaiseAttribute(self,SelfTrigger.AIVariables[1], -SelfTrigger.AIVariables[2]);
        attribute_TimeBonus = 0;
        return LOOP_END;
    };

    return LOOP_CONTINUE;
};

собрал проект. добавил функцию которая меняет атрибуты, инстанции зелий. тестировал на НВ. архив с проектом прилагаю.

Я конечно хотел бы максимально задействовать стандартные функции, но спасибо, пока ничего непонятно, но постараюсь разобраться)
 
Последнее редактирование:

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.001
Благодарности
969
Баллы
295
Я конечно хотел бы максимально задействовать стандартные функции
закинь архив в папку авторан и проверь как оно работает в игре. если оно в целом тебе подходит тогда можно разбираться что там и как оно работает.
Параметры в отдельном файле с инстанциям зелий.

вся информация о свойствах зелий находится непосредственно в инстанции.
Daedalus:
INSTANCE ItPo_Bonus_STR(C_Item)
{
    ItPo_Perm_STR();
 
    on_state[0] = UseItPo_TimeBonus;
    
    cond_atr[1] = ATR_STRENGTH;           // атрибут который меняем
 
    TEXT[1]        = NAME_Bonus_Str;       COUNT[1] =     STR_Bonus_Elixier;      // на сколько меняется атрибут
    TEXT[2]        = NAME_Sec_Duration;    COUNT[2] =     Time_Bonus_STR ;        // сколько секунд длится эффект
};
Для on_state[0] зелий идёт общая функция UseItPo_TimeBonus которая берёт информация из item.
Daedalus:
    func void UseItPo_TimeBonus()
    { 
        if (Attribute_TimeBonus == 0)
        {
            // кому меняем, что меняем, на сколько меняем, сколько буде длится эффект
            Start_Trigger_Attribute_TimeBonus(self, item.cond_atr[1], item.COUNT[1],item.COUNT[2]);
        }
        else // передоз
        {
            AI_Wait (hero,3);
            AI_PlayAni (self, "S_FIRE_VICTIM"); 
            Wld_PlayEffect("VOB_MAGICBURN",  hero, hero, 0, 0, 0, FALSE );
            B_Say (self,self, "$Dead");
            AI_StopFX    (self, "VOB_MAGICBURN");
            Npc_ChangeAttribute    (self,ATR_HITPOINTS,-self.attribute[ATR_HITPOINTS_MAX]);    
            NPC_StopAni (self,"S_FIRE_VICTIM");
        };
    };
Пост автоматически объединён:

для необычных зелий можно использовать и индивидуальную функцию.
Daedalus:
func void UseItPo_WND_WolfSoul()
{
            Start_Trigger_Attribute_TimeBonus(self, ATR_STRENGTH, STR_WolfSoul,Time_Bonus_STR );
            Start_Trigger_Attribute_TimeBonus(self, ATR_DEXTERITY, DEX_WolfSoul,Time_Bonus_Dex );
   // WolfSoul_Used = TRUE;
};
 
Последнее редактирование:

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.301
Благодарности
4.636
Баллы
625
получилось просто, понятно и быстро.
Рекомендую внимательно прочитать про локальный и глобальный триггеры.
Локальный триггер выполняется в пределах текущего мира. Нужен для того, чтобы привязать таймеры к конкретному НПС. Соответственно, если хотя бы один нпс триггера не null, то триггер будет локальным.

Поэтому для зелий, которые применяются к гг, рекомендуется создавать триггер без привязки к кому либо (использовать функцию создания без Ex, либо везде указывать null), а в теле триггерной функции обращаться напрямую к hero. Таким образом, он сможет работать даже при переходе между локациями.
 

KirTheSeeker

Участник форума
Регистрация
18 Авг 2017
Сообщения
1.928
Благодарности
557
Баллы
275
KirTheSeeker,

Daedalus:
func void G_PickLock(var int bSuccess,var int bBrokenOpen)
{
    var int rnd;
    var int DEX_Lock_KTS_1   ;
    DEX_Lock_KTS_1 = hero.attribute[ATR_DEXTERITY] / 10;
   
    if(UnionPickLockStrNum >= DEX_Lock_KTS_1)
    {
        Print("Нужно больше ловкости.");
AI_PlayAni(hero,"T_CHESTBIG_S0_2_STAND"); // Проигрывание анимации вставания от сундука. Видимое прекращение взаимодействия.
AI_UseMob(hero,"CHESTBIG",-1); // Формальное прекращение взаимодействия с сундуком. По окончании на экран выводится надпись.
AI_PlayAni(hero,"T_DONTKNOW"); // Проигрывание анимации пожимания плечами.
AI_OutputSVM(hero,hero,"$NEEDKEY"); // Произнесение комментария "Для этого мне нужен ключ."
AI_Wait(hero,0.2); // Пауза.
//        B_Say_Overlay(self,self,"$MISSINGITEM");
    };
...
Пост автоматически объединён:


он вроде изначально хотел что бы герой садился ковырялся в замке , а потом "понимал" что у него мало ловкости :)
Работает корректно, однако вызывает вопросы сам расчёт, а точнее:
Для открытия сундука с 5 поворотами, потребовалось 60 ловкости, вместо 50. Даже при 55 ГГ не способен продолжить вскрытие.

Благодарю всех за ответы.
Пост автоматически объединён:

Daedalus:
var int UnionPickLockStrNum;

func void G_PickLock(var int bSuccess,var int bBrokenOpen)
{
    var int rnd;
    var int DEX_Lock_KTS_1   ;
    DEX_Lock_KTS_1 = hero.attribute[ATR_DEXTERITY] / 10;
    
    if(UnionPickLockStrNum >= DEX_Lock_KTS_1)
    {
        Print("Нужно больше ловкости.");
        AI_PlayAni(hero,"T_CHESTBIG_S0_2_STAND"); // Проигрывание анимации вставания от сундука. Видимое прекращение взаимодействия.
        AI_UseMob(hero,"CHESTBIG",-1); // Формальное прекращение взаимодействия с сундуком. По окончании на экран выводится надпись.
        AI_PlayAni(hero,"T_DONTKNOW"); // Проигрывание анимации пожимания плечами.
        AI_OutputSVM(hero,hero,"$MISSINGITEM"); // Произнесение комментария "И как я это сделаю?"
        AI_Wait(hero,0.2); // Пауза.
    };
    ...

Возможно, вместо hero.attribute[ATR_DEXTERITY] стоит прописать (ATR_Training[ATR_DEXTERITY] + ATR_PermBonus[ATR_DEXTERITY] + ATR_TempBonus[ATR_DEXTERITY]) ? Или проблема может быть в UnionPickLockStrNum >= DEX_Lock_KTS_1 ?
 
Последнее редактирование:

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
Для открытия сундука с 5 поворотами, потребовалось 60 ловкости, вместо 50. Даже при 55 ГГ не способен продолжить вскрытие.
Вот здесь

Daedalus:
DEX_Lock_KTS_1 = hero.attribute[ATR_DEXTERITY] / 10;

используется целочисленное деление. Переменная не может иметь дробной части. Дробная часть отбрасывается. При значениях ловкости от 50 до 59 результат деления будет равен 5.
 

KirTheSeeker

Участник форума
Регистрация
18 Авг 2017
Сообщения
1.928
Благодарности
557
Баллы
275
используется целочисленное деление. Переменная не может иметь дробной части. Дробная часть отбрасывается. При значениях ловкости от 50 до 59 результат деления будет равен 5.
Я протупил. Для корректной работы достаточно просто убрать равно, оставив:
Daedalus:
if(UnionPickLockStrNum > DEX_Lock_KTS_1)
 
Последнее редактирование:

KirTheSeeker

Участник форума
Регистрация
18 Авг 2017
Сообщения
1.928
Благодарности
557
Баллы
275
Я протупил. Для корректной работы достаточно просто убрать равно, оставив:
Daedalus:
if(UnionPickLockStrNum > DEX_Lock_KTS_1)
Протестировал. Теперь всё работает как нужно.

ElderGamer, а в G1 ведь 2 уровня взлома?
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
В классической Г1 можно изучить два уровня навыка отрытия замков отмычками. Величина навыка влияет только на шанс сломать отмычку при неправильной попытке.
 

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.001
Благодарности
969
Баллы
295
Рекомендую внимательно прочитать про локальный и глобальный триггеры.
читал и перечитывал. и примеры N1kX с огненным луком смотрел.

рекомендуется создавать триггер без привязки к кому либо (использовать функцию создания без Ex, либо везде указывать null), а в теле триггерной функции обращаться напрямую к hero. Таким образом, он сможет работать даже при переходе между локациями.
описанный способ прекрасно подходит для квестов, когда нужно найти какой то предмет. Например "кошелёк Диего" или "глаз инноса". Тогда триггер можно "запустить" в той же функции диалога где герою дают информацию/квест. а когда герой найдёт предмет, пусть даже другом мире, триггер сработает и добавить запись в дневник и / или изменить статус квеста и/или произведёт иные действия. Сейчас в проектах ElderGamer и D36 используются цикличные функции для реализации подобных действий. Возможно вынос подобных в моментов в отдельные триггеры могло бы упростить код с точки зрения структуры. Это с одной стороны. С другой стороны, примеров реализации Триггеров на zparser почти нет, поэтому они остаются недооцененными :) как писал классик - Привычка свыше нам дана: Замена счастию она.

а вот для зелий всё таки лучше использовать триггер с привязкой к НПС, что бы иметь возможно полноценно использовать его. например: герой даёт некое зелье НПС_Пирату, проигрывается анимация выпивания зелья и на данного НПС_Пирату запускается триггер на минуту повышающий его силу. НПС_Пирату экипирует какой то крутой меч и он далее с этим оружием начинает навязывать свою волю :) или вот прям в Ночь Ворона квест: пират выпивает быструю селёдку и через триггер на него можно наложить ускорение на одну минуту. Или зелье на время включающее регенерацию ХП или что то там еще. Из этих соображений я и написал его "с заделом" так как не знаю для чего именно он будет использован.
Пост автоматически объединён:

@ElderGamer, а в G1 ведь 2 уровня взлома?
смотря как считать;-)
  • 0 уровень, вероятность провала 90%
  • 1 уровень, вероятность провал 50%
  • 2 уровень, вероятность провал 10%
при провале герой ломает отмычку и прекращает взаимодействия с сундуком. если стоит zPicklockAnis то еще и пинает сундук. в случае провала рядом нахолящемся НПС посылается инфа о воровстве. но оно работает не всегда корректно:)
 
Последнее редактирование:

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.301
Благодарности
4.636
Баллы
625
а вот для зелий всё таки лучше использовать триггер с привязкой к НПС, что бы иметь возможно полноценно использовать его.
Триггер надо делать так, чтобы логика была универсальна к ситуациям, когда эффект должен накладываться и локально, и глобально. Небольшое разветвление поможет.

Daedalus:
func void on_drink_something() {
    G_StartTrigger(self, ...)
}

...

func void G_StartTrigger(var C_Npc slf, ...) {
    var C_Trigger trigger;
    if (Npc_IsPlayer(slf)) {
        trigger = AI_StartTriggerScript(...) // global trigger
    }
    else {
        trigger = AI_StartTriggerScriptEx(..., slf) // local trigger
    }
}

...

func int trigger_logic() {
    var C_Npc npc;
    if (Hlp_IsNull(self)) {
        npc = hero;
    }
    else {
        npc = self;
    }
 
    ... // TODO with npc
}
 

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.001
Благодарности
969
Баллы
295
когда эффект должен накладываться и локально, и глобально.
глобально это надо учитывать:
  1. меняется ли мир первый раз или нет
  2. была ли смена времени при смене мира или нет
  3. был ли это переход на Ирдорат или нет
тот кто может всё это детально проработать и учесть тот может и сам разобраться с триггерами и настроить их под себя, зная все возможные моменты.
Небольшое разветвление поможет.
после этого ещё сделать ряд доп проверок и только потом уже осознанно решится на то что бы триггер сделать глобальным и сохранить эффект повышения атрибута для героя при смене мира ;-) вот это локализация кода на Ночь Ворона и я такой забор не построю, так как не знаю на столько хорошо все аспекты игры Ночь Ворона. то что пишешь ты это есть идеальная концепция.
 
Последнее редактирование:
Сверху Снизу