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

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

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

MaGoth

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

Вложения

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

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.167
Баллы
915
Чтобы у него был шанс "застукать" ГГ на вскрытии сундуков. Сам же знаешь, что на склад можно нелегально попасть и без усыпления этого стражника.
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
Тут варианты есть разные. Можно задействовать восприятия стражника. В восприятии ГГ (PERC_ASSESSPLAYER) можно контролировать нахождение ГГ в окрестностях находящегося около сундука вейпоинта. Можно проверить режим его передвижения (крадётся или нет). Можно проверить, находится ли он в состоянии взаимодействия с сундуком. Также можно использовать восприятие взаимодействия мобом (PERC_ASSESSUSEMOB), проверяя, что ГГ вскрывает именно сундук и именно ТОТ сундук.

Вопрос в том, чтобы вся эта кухня не слишком осложнила жизнь игроку. Иначе, добывание данного "халявного" доспеха станет нерациональным, а это не верный путь, как мне кажется.

P. S. Кстати, а насколько верен пункт, что стражника нельзя усыпить. На мой взгляд, интереснее было бы, чтобы возможность усыпления существовала. Ну, может, это было бы сложнее, чем усыпление обычного непися. ;)
 

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.167
Баллы
915
Наоборот, его можно усыпить, об этом прямо говорит Ларес, когда ГГ спрашивает, как достать доспех получше. Я хочу усложнить нелегальный способ проникновения на склад, связанный с ползанием по стене или крышам домов.
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
Понятно. Помню, что усыпить в Г2 можно не всех. Попутал немного.

Кстати, тот факт, что стражник увидит ГГ, стоящего около сундуков или открывающего их, ничего не изменит. Алгоритм диалогов охранника прохода основан только на контроле расстояния до чекпоинта. Формально, территория там ничейная, сундуки, скорее всего, тоже ничейные. С точки зрения ИИ предъявить нечего.

Используй восприятия. Можно не перегружать стандартные функции дополнительными проверками. Создай свои функции для обработки восприятий конкретно этого непися.
func void ZS_Guard_Passage()
{
Perception_Set_Normal();
if(self.id == 325)
{
// Переназначение функций-обработчиков восприятий.
Npc_PercEnable(self,PERC_ASSESSPLAYER,B_AssessPlayer_325);
Npc_PercEnable(self,PERC_ASSESSUSEMOB,B_AssessUseMob_325);
};

B_ResetAll(self);
Npc_SetPercTime(self,0.1);
AI_Standup(self);
AI_SetWalkMode(self,NPC_WALK);
AI_GotoWP(self,self.wp);
if(Npc_GetDistToNpc(self,hero) > PERC_DIST_DIALOG)
{
AI_AlignToWP(self);
};
};

func int ZS_Guard_Passage_Loop()
{
if(Npc_GetStateTime(self) >= 3)
{
if(Npc_GetDistToNpc(self,hero) > PERC_DIST_DIALOG)
{
AI_AlignToWP(self);
Npc_SetStateTime(self,0);
};
};
return LOOP_CONTINUE;
};

func void ZS_Guard_Passage_End()
{
};

func void B_AssessPlayer_325()
{
// Здесь прописать особую реакцию на ГГ.
// ...
B_AssessPlayer();
};

func void B_AssessUseMob_325()
{
// Здесь прописать особую реакцию на открытие сундуков.
// ...
B_AssessUseMob();
};
 

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.167
Баллы
915
Похоже, что мне придётся отказаться от усложнения задачи по нелегальному проникновению ГГ на склад за лавкой Маттео. Исследование свойств находящихся там сундуков показало, что они безымянные, ничейные и территория склада не принадлежит ни одной из городских гильдий. Поэтому когда я подводил стражника вплотную к этим сундукам и на его глазах обчищал их, тот не обращал на действия ГГ никакого внимания.
 

НастасьСанна

Участник форума
Регистрация
6 Дек 2012
Сообщения
350
Благодарности
521
Баллы
325
Можно добавить условие в C_IsUsedMobMyPossession:
Код:
  // я стражник, а ГГ лезет в сундуки Матеео
   if ((slf.guild == GIL_MIL) && (Npc_GetDistToWP(oth,"NW_CITY_MERCHANT_PATH_03") < 500)) //проверить расстояние
   {
     return TRUE;
   };
С поворотами может быть труднее. Через Икарус я делала поворот на произвольный угол, но как это реализовать стандартными средствами, не знаю. Предлагаю, чтобы он иногда заходил внутрь дворика, через правку ZS_Guard_Passage_Loop:
Код:
func int ZS_Guard_Passage_Loop()
{
   // если я уже 3сек. стою
   if(Npc_GetStateTime(self) >= 3)
   {
     // и ГГ не подошел слишком близко
     if(Npc_GetDistToNpc(self,hero) > PERC_DIST_DIALOG)
     {
       //если я стражник, охраняющий сундуки Маттео
       if (Hlp_GetInstanceID(self) == Hlp_GetInstanceID(Mil_325_Miliz))
       {
         var random;   random = Hlp_Random(5);
         if (random == 0) //в 20% случаев
         {
           AI_GoToWP(self,"NW_CITY_MERCHANT_PATH_03"); //WP внутри дворика
           AI_PlayAni(self,"T_HGUARD_LOOKAROUND");
         }
         else   //возвращаемся назад
         {
           AI_GotoWP(self,self.wp);
           AI_AlignToWP(self);
         };
       }
       else   //обычное поведение
       {
         // подравняться
         AI_AlignToWP(self);
       };
       // и сбросить таймер
       Npc_SetStateTime(self,0);
     };
   };
   return LOOP_CONTINUE;
};
 

ElderGamer


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

Кстати, а насколько логично, что стражник не пропускает к сундукам мага Огня?
 

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.167
Баллы
915
Это нелогично, но тогда придётся добавлять для этого NPC новую инстанцию диалога, например:
Код:
instance DIA_Mil_325_Miliz_PassAsMage(C_Info)
{
npc = MIL_325_Miliz;
nr = 5;
condition = DIA_Mil_325_Miliz_PassAsMage_Condition;
information = DIA_Mil_325_Miliz_PassAsMage_Info;
permanent = FALSE;
description = "Я маг Огня.";
};
 
func int DIA_Mil_325_Miliz_PassAsMage_Condition()
{
if((self.aivar[AIV_PASSGATE] == FALSE) && (other.guild == GIL_KDF))
{
return TRUE;
};
};
 
func void DIA_Mil_325_Miliz_PassAsMage_Info()
{
AI_Output(other,self,"DIA_PAL_205_Torwache_PassAsMage_15_00"); //Я маг Огня.
AI_Output(self,other,"DIA_Mil_325_Miliz_Pass_Yes_12_01"); //Хорошо, ты можешь войти!
self.aivar[AIV_PASSGATE] = TRUE;
AI_StopProcessInfos(self);
};
Также после получения разрешения на вход нелогично выглядит вопрос ГГ "Почему никому нельзя входить на этот склад?", поэтому нужно изменить условие:
Код:
func int DIA_Mil_325_Miliz_PERM_Condition()
{
if(self.aivar[AIV_PASSGATE] == FALSE)
{
return TRUE;
};
};

К сожалению, предложенный НастасьСанной способ не работает, т.к. можно на виду у стражника спокойно обчистить сундуки на этом складе.
 
Последнее редактирование:

НастасьСанна

Участник форума
Регистрация
6 Дек 2012
Сообщения
350
Благодарности
521
Баллы
325
Возможно, это создаст лазейку для обмана алогоритма диалогов по непропуску ГГ в дворик. Если на стадии перехода к чекпоинту стражник не будет видеть ГГ и не сможет, по этой причине, начать диалог, то возможен следующий трюк.
Тогда можно на WP внутри дворика вставлять невидимого жука, и чтобы стражник поворачивался к этому жуку.
 

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.167
Баллы
915
Какой смысл делать это, если у этого стражника просто не включается восприятие "Грабят!"? Тогда пусть он стоит на месте и хотя бы периодически осматривается.
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
у этого стражника просто не включается восприятие "Грабят!"

Вот для исправления и нужно использовать особую реакцию при обработке восприятий. Например, особая реакция на ГГ может отработать следующий сценарий. ГГ прыгает вниз со стены, Стражник "слышит" звук и оборачивается. Если он видит ГГ во внутреннем пространстве дворика, то называет его вором и начинает атаковать. Если ГГ стражник не видит, тот стоит за углом здания, но "звук был достаточно сильным", поскольку ГГ экипирован тяжёлым доспехом или оружие звякнуло при падении, то стражник пойдёт внутрь дворика и обнаружит там ГГ. Если ГГ экипирован в лёгкий доспех и не имеет экипированного оружия, то стражник просто обернётся, посмотрит внутрь дворика (на стоящего за углом ГГ), подождёт немного и отвернётся, подумав, что ему показалось. После этого ГГ может, передвигаясь в режиме подкрадывания, обчистить сундуки. Выбираться назад нужно также через забор. Действия ГГ контролируюся с помощью контроля состояния тела ГГ (BS-константы), контроля видимости между ним и стражником и контроля расстояния между ГГ и чекпоинтом.

Кстати, насколько оправданы названия "Тяжёлая одежда горожанина", "Средняя одежда горожанина"... ? Может, подсократить названия до "Одежда горожанина"? Тем более, что параметры защиты у них одинаковые.
 

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.167
Баллы
915
Кстати, насколько оправданы названия "Тяжёлая одежда горожанина", "Средняя одежда горожанина"... ? Может, подсократить названия до "Одежда горожанина"? Тем более, что параметры защиты у них одинаковые.
Оправданы, потому что в неофициальном обновлении одежда будет иметь разные уровни защиты от режущего/дробящего/стрел, например,
горожане и горожанки: лёгкая 10/10/10, средняя 15/15/10, тяжёлая 15/15/15;
крестьяне и крестьянки: лёгкая 15/15/10, средняя 15/15/15.
Интересно, а почему украденная со склада одежда горожан собрана в пачки (5 штук лёгкая и 3 - средняя)? Ведь когда вставляешь её кодом, тогда в инвентаре она не собирается в пачки.
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
Оправданы, потому что в неофициальном обновлении одежда будет иметь разные уровни защиты
Ну, тут больше речь не о защите, а о том, что подобные словосочетания режут слух. Когда говорят о доспехе, то дополнительная характеристика "лёгкий" или "тяжёлый" более-менее привычна. Но когда говорят об одежде... Лёгкая одежда у меня, например, ассоциируется с майкой и шортами а тяжёлая одежда... просто режет слух нелепостью словосочетания. ;) В данном случае использование типовой классификации не прокатывает, нужно использовать другой подход. Например: "Одежда ремесленника", Одежда богатого горожанина" и т. д.

Интересно, а почему украденная со склада одежда горожан собрана в пачки (5 штук лёгкая и 3 - средняя)? Ведь когда вставляешь её кодом, тогда в инвентаре она не собирается в пачки.

Возможно, дело в том, что движок модифицирует предметы флагами. Например, если взять предмет, лежащий на земле изначально, и потом выбросить его назад на землю, то это будет не совсем тот же предмет. У предмета изменится значение флага. По этому признаку, кстати, в скриптах различается, украл ли ГГ что-то или поднял свою вещь, выброшенную из инвентаря.

Заметил недоработку в скриптах Г2НВ. Зомби причислены к числу монстров, поедающих свои жертвы (функция C_WantToEat). Однако нужной анимации они не имеют. Думаю, правильно будет, исключить зомби из списка охотников/падальщиков.

Есть в скриптах такая функция B_MM_DeSynchronize. Предназначена она для внесения рандомной задержки в действия монстров, чтобы их синхронные действия не слишком бросались в глаза.

Код:
func void B_MM_DeSynchronize()
{
   var int msec;
   msec = Hlp_Random(1000);
   AI_Waitms(self,msec);
};

Однако, из-за кривой работы рандомизера движка, результат работы функции минимален. Близкие по времени выборки дают близкие результаты, поэтому для конкретной группы монстров задержки будут почти одинаковыми, и рассинхронизации, по-факту, не произойдёт. Предлагаю альтернативный вариант функции.

Код:
func void B_MM_DeSynchronize()
{
   var int random1;
   var int random2;
   random1 = Hlp_Random(100);
   random2 = random1%5;
   if(random2 == 1)
   {
     AI_Wait(self,0.3);
   }
   else if(random2 == 2)
   {
     AI_Wait(self,0.6);
   }
   else if(random2 == 3)
   {
     AI_Wait(self,0.9);
   }
   else if(random2 == 4)
   {
     AI_Wait(self,1.2);
   };
};
 

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.167
Баллы
915
Заметил недоработку в скриптах Г2НВ. Зомби причислены к числу монстров, поедающих свои жертвы (функция C_WantToEat). Однако нужной анимации они не имеют. Думаю, правильно будет, исключить зомби из списка охотников/падальщиков.
Спасибо, исключил зомби из списка пожирателей своих жертв.
Есть в скриптах такая функция B_MM_DeSynchronize. Предназначена она для внесения рандомной задержки в действия монстров, чтобы их синхронные действия не слишком бросались в глаза.

Однако, из-за кривой работы рандомизера движка, результат работы функции минимален. Близкие по времени выборки дают близкие результаты, поэтому для конкретной группы монстров задержки будут почти одинаковыми, и рассинхронизации, по-факту, не произойдёт. Предлагаю альтернативный вариант функции.
Хорошо, попробую твой вариант. Кстати, в нём вполне можно обойтись одной переменной random:
Код:
func void B_MM_DeSynchronize()
{
  var int random;
   random = Hlp_Random(100) % 5;
   if(random == 1)
   {
     AI_Wait(self,0.3);
   }
   else if(random == 2)
   {
     AI_Wait(self,0.6);
   }
   else if(random == 3)
   {
     AI_Wait(self,0.9);
   }
   else if(random == 4)
   {
     AI_Wait(self,1.2);
   };
};
Ну, тут больше речь не о защите, а о том, что подобные словосочетания режут слух. Когда говорят о доспехе, то дополнительная характеристика "лёгкий" или "тяжёлый" более-менее привычна. Но когда говорят об одежде... Лёгкая одежда у меня, например, ассоциируется с майкой и шортами а тяжёлая одежда... просто режет слух нелепостью словосочетания. ;) В данном случае использование типовой классификации не прокатывает, нужно использовать другой подход. Например: "Одежда ремесленника", Одежда богатого горожанина" и т. д.
Из предложенного тобой подходит только одежда богатого горожанина, потому что её обычно носят жители верхнего квартала. Мне удалось подобрать более или менее удачные названия для одежды крестьян:
рабочая одежда крестьянина (ITAR_Bau_L), одежда крестьянина (ITAR_Bau_M), рабочая одежда крестьянки (ITAR_BauBabe_L), одежда крестьянки (ITAR_BauBabe_M)
, но с одеждой горожан пока ничего не выходит, например, не годится одежда ремесленника, т.к. её носят NPC, не имеющие никакого отношения к ремесленникам. Поэтому пока я оставил так:
легкая одежда горожанина (ITAR_Vlk_L), одежда горожанина (ITAR_Vlk_M), одежда богатого горожанина (ITAR_Vlk_H), легкая одежда горожанки (ITAR_VlkBabe_L), одежда горожанки (ITAR_VlkBabe_M), одежда богатой горожанки (ITAR_VlkBabe_H).

Заметил, что среди C-функций нигде не используются всегда возвращающие значение TRUE C_BanditAttackBandit(var C_Npc slf,var C_Npc oth) и C_BanditHelpsStoryBandit(var C_Npc slf,var C_Npc oth,var C_Npc vct). Даже в G2 MDK насчёт них нет никакой дополнительной информации.
 
Последнее редактирование:

Vlad_Torop

Участник форума
Регистрация
2 Май 2014
Сообщения
870
Благодарности
499
Баллы
230
А вот такой вариант?:
Роба крестьянина(крестьянки),крепкая роба крестьянина(крестьянки)
Одежда горожанина(горожанки),цивильная одежда горожанина(горожанки),дорогая одежда горожанина(горожанки)
 

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.167
Баллы
915
@Vlad_Torop:
Не пойдёт, т.к.:
- для крестьянской одежды уже есть удачные названия, например, ITAR_Bau_L Лобарт называет рабочей крестьянской одеждой;
- режет слух выпадающее из сеттинга игры слово "цивильная".
P.S.: предлагаю перенести дискуссию о названиях одежды в тему Готика 2: Общее обсуждение.
 
Последнее редактирование:

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
Обнаружил ошибку, благодаря которой смена распорядков у монстров происходит не совсем правильно. Так, например, у падальщика должны сменять друг друга распорядки сна (ZS_MM_Rtn_Sleep) и кормёжки (ZS_MM_Rtn_EatGround). Но из-за ошибки в Г2 происходит переход на промежуточный распорядок ZS_MM_Rtn_Rest, и только после этого на нужный распорядок. В Г1 вообще происходит ступор в дефолтном распорядке. Причина в том, что для выхода из одного распорядка и вхождения в другой распорядок используется контроль промежутков времени, а в момент смены счётчик времени находится "между" этими промежутками, один промежуток закончился, а другой ещё не наступил.

Для исправления ошибки достаточно задержать выход из текущего распорядка на минуту.
if(!Wld_IsTime(self.aivar[AIV_MM_SleepStart],0,self.aivar[AIV_MM_SleepEnd],0) && (self.aivar[AIV_MM_SleepStart] != OnlyRoutine))
if(!Wld_IsTime(self.aivar[AIV_MM_SleepStart],0,self.aivar[AIV_MM_SleepEnd],1) && (self.aivar[AIV_MM_SleepStart] != OnlyRoutine))

Но лучше ввести дополнительную рассинхронизацию, чтобы падальщики после сна, например, не вскакивали, как по команде "Рота, подъём!"
Код:
func void ZS_MM_Rtn_Sleep()
{
   ...
   self.aivar[AIV_MM_StateTime] = Hlp_Random(100)%8 + 1; // Задержка перехода к следующему распорядку (минуты).
};

func int ZS_MM_Rtn_Sleep_loop()
{
   if(!Wld_IsTime(self.aivar[AIV_MM_SleepStart],0,self.aivar[AIV_MM_SleepEnd],self.aivar[AIV_MM_StateTime]) && (self.aivar[AIV_MM_SleepStart] != OnlyRoutine))
   ...
};
 

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.167
Баллы
915
Это касается только выхода из распорядка сна ZS_MM_Rtn_Sleep() или же проблема существует и для остальных распорядков монстров? Потому что в них используется такое же условие перехода из текущего распорядка в новый:
ZS_MM_Rtn_Wusel(), ZS_MM_Rtn_Roam(), ZS_MM_Rtn_Rest(), ZS_MM_Rtn_OrcSit(), ZS_MM_Rtn_EatGround(), ZS_MM_Rtn_DragonRest().
P.S.: Т.к. в G2 нет aivar[AIV_MM_StateTime], вместо неё надо использовать aivar[AIV_StateTime].
 
Последнее редактирование:

ElderGamer


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

Да, это проблема всех распорядков, но проявляется только для монстров, у которых подразумевается смена распорядка по ходу дня.

Т.к. в G2 нет aivar[AIV_MM_StateTime], вместо неё надо использовать aivar[AIV_StateTime].
Ага.
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
И ещё один момент. В функции B_MM_AssessOthersDamage есть любопытный эпизод.

Код:
func void B_MM_AssessOthersDamage()
{
   ...
   if(self.guild == GIL_WOLF)
   {
     if((victim.guild == GIL_WOLF) && (other.guild == GIL_WOLF) && Npc_IsPlayer(other) && Npc_IsDead(victim))
     {
       Npc_ClearAIQueue(self);
       B_ClearPerceptions(self);
       self.start_aistate = ZS_MM_Rtn_Summoned;
       AI_StartState(self,ZS_MM_Rtn_Summoned,0,"");
       return;
     };
   };
  ...
};

Смысл в следующем. Если ГГ в образе волка убьёт настоящего волка на виду у ещё одного волка, то волк-свидетель, как будто бы, признает в ГГ вожака и будет следовать за ним, как призванный волк. Проблема в том, что когда ГГ в образе волка попытается "завербовать" себе ещё одного спутника таким же образом, другой, не завербованный ещё волк-свидетель начинает атаковать своего собрата, а затем и ГГ. На мой взгляд, здесь имеет место ошибка. Причина, видимо, находится в функции B_MM_AssessWarn, где не предусмотрен такой вариант событий.

И, кстати, кабаны тоже по гильдии волки, поэтому возможны совсем уж глупые ситуации. :)
 
Сверху Снизу