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

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

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

MaGoth

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

Вложения

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

alexel

Участник форума
Регистрация
28 Апр 2014
Сообщения
12
Благодарности
0
Баллы
165
Мда, пробовал полчаса назад
if(Npc_GetTarget(hero) && Hlp_IsValidNpc(other))
{

};
Не прокатило, ваш скрипт пошел) Учиться еще и учиться) спасибо)
А сам триггер работает? Он точно работает как циклический?
Ага, много чего на нем висит, так что однозначно работает)
Все уже, заработало)
 

Myxomop

Почетный форумчанин
Регистрация
28 Май 2005
Сообщения
3.239
Благодарности
2.581
Баллы
455
if(Npc_GetTarget(hero) && Hlp_IsValidNpc(other))
Такая связка и у меня приводила к неработоспособности в некоторых вариантах, при надобности Hlp_IsValidNpc(other)) проверял уже внутри условия.
 

alexel

Участник форума
Регистрация
28 Апр 2014
Сообщения
12
Благодарности
0
Баллы
165
Хм, подскажите, есть ли какая функция проверяющая загрузку сейва. Объясняю, мне хотелось бы что-бы после загрузки сейва некоторые переменные устанавливались на нужные мне показатели.
 

Jr13San


Модостроитель
Регистрация
1 Апр 2010
Сообщения
449
Благодарности
266
Баллы
230
alexel, попробуй написать условия внутри тела инстанции "PC_Hero". Она ведь тоже загружается при каждой загрузке ваших сохранений. Можешь протестировать её ещё после перехода на новый ZEN-уровень.
Попробуй сначала c простейшей функцией вывода текста на экран, т.е. примерно так:
instance PC_Hero(Npc_Default)
{
name[0] = "Я";
guild = GIL_NONE;
id = 100;
voice = 15;
level = 0;
npcType = npctype_main;
bodyStateInterruptableOverride = TRUE;
exp = 0;
exp_next = 500;
lp = 0;
attribute[ATR_STRENGTH] = 20;
attribute[ATR_DEXTERITY] = 20;
attribute[ATR_MANA_MAX] = 10;
attribute[ATR_MANA] = 10;
attribute[ATR_HITPOINTS_MAX] = 40;
attribute[ATR_HITPOINTS] = 40;
Mdl_SetVisual(self,"HUMANS.MDS");
Mdl_SetVisualBody(self,"hum_body_Naked0",9,0,"Hum_Head_Pony",Face_N_Player,0,NO_ARMOR);
B_SetFightSkills(self,10);
PrintScreen("test print",-1,-1,FONT_SCREEN,10);//тест
};
 

alexel

Участник форума
Регистрация
28 Апр 2014
Сообщения
12
Благодарности
0
Баллы
165
Она ведь тоже загружается при каждой загрузке ваших сохранений
не, не загружается) Что в общем-то логично, если бы загружалась, сбрасывались бы статы, опыт, уровни итд...) Я думаю все текущие настройки, которые загружаются, могут хранится в классе hero. Вот только там изменять не совсем удобно)
 

ElderGamer


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

А функции инициализации из startupа не подойдут?
 

Jr13San


Модостроитель
Регистрация
1 Апр 2010
Сообщения
449
Благодарности
266
Баллы
230
не, не загружается)
У меня тогда срабатывало в двух случаях:
1) После загрузки из уже загруженной локации.
2) После "начала новой игры", также, из уже загруженной локации.
Ну вообщем-то это не самый надёжный способ, как показывает практика.

Я попробую рассказать про другой - более интересный и надёжный способ. Он основан на изменении свойств инстанции после загрузки. Опять после загрузки, но здесь речь пойдёт немножко о другом. Для примера возьмём стандартную инстанцию нашего Player Controller'a:
instance PC_Hero(Npc_Default)
{
name[0] = "Я";
guild = GIL_NONE;
id = 0;
voice = 15;
level = 0;
npcType = npctype_main;
bodyStateInterruptableOverride = TRUE;
exp = 0;
exp_next = 500;
lp = 0;
attribute[ATR_STRENGTH] = 10;
attribute[ATR_DEXTERITY] = 10;
attribute[ATR_MANA_MAX] = 10;
attribute[ATR_MANA] = 10;
attribute[ATR_HITPOINTS_MAX] = 40;
attribute[ATR_HITPOINTS] = 40;
Mdl_SetVisual(self,"HUMANS.MDS");
Mdl_SetVisualBody(self,"hum_body_Naked0",9,0,"Hum_Head_Pony",Face_N_Player,0,NO_ARMOR);
B_SetFightSkills(self,10);
};

Как видишь, у него есть имя: "Я" - это значение по умолчанию.
Если его динамически поменять во время игры, то оно изменится, но не сохранится навсегда, а лишь до ближайшей загрузки игры. После загрузки сохранения его имя вновь примет значение по умолчанию.
Вот как раз здесь можно и "сыграть"! То есть меняем ему имя и ждём пока оно само не изменится. Если изменилось, значит была загрузка.

Отслеживать будем с помощью триггер-скрипта, зацикленного самого на себя.
Свойства триггер-скрипта из редактора Spacer:
TR_TESTEVENT.jpg
Интервал (fireDelaySec = 1 сек.)
Название триггер-скрипта и его функции совпадают - "TR_TESTEVENT".

Если стартуем на NEWWORLD.ZEN, то запускаем его, например, из этой функции:
func void INIT_NewWorld()
{
B_InitMonsterAttitudes();
B_InitGuildAttitudes();
B_InitNpcGlobals();
b_enter_newworld();
if(Diebesgilde_Verraten && (Andre_Diebesgilde_aufgeraeumt != TRUE))
{
if(!Npc_IsDead(Cassia) || !Npc_IsDead(Jesper) || !Npc_IsDead(Ramirez))
{
B_KillNpc(VLK_447_Cassia);
B_KillNpc(VLK_446_Jesper);
B_KillNpc(VLK_445_Ramirez);
Andre_Diebesgilde_aufgeraeumt = TRUE;
};
};
INIT_SUB_NewWorld_Part_City_01();
INIT_SUB_NewWorld_Part_Farm_01();
INIT_SUB_NewWorld_Part_Xardas_01();
INIT_SUB_NewWorld_Part_Monastery_01();
INIT_SUB_NewWorld_Part_GreatPeasant_01();
INIT_SUB_NewWorld_Part_TrollArea_01();
INIT_SUB_NewWorld_Part_Forest_01();
INIT_SUB_NewWorld_Part_Pass_To_OW_01();
if((MIS_ReadyForChapter3 == TRUE) && (B_Chapter3_OneTime == FALSE))
{
B_Kapitelwechsel(3,NEWWORLD_ZEN);
B_Chapter3_OneTime = TRUE;
};
if((MIS_AllDragonsDead == TRUE) && (B_Chapter5_OneTime == FALSE))
{
B_Kapitelwechsel(5,NEWWORLD_ZEN);
B_Chapter5_OneTime = TRUE;
};

Wld_SendTrigger("TR_TESTEVENT");//делаем первый запуск триггер-скрипта
};

А вот и сама функция триггер-скрипта:
//Интервал = 1 сек.
func void TR_TESTEVENT()
{
var C_NPC npc;//объявляем переменную
npc = Hlp_GetNpc(PC_Hero);//помещаем в эту переменную ссылку на ГГ

if (Npc_IsPlayer(npc))//если под управлением находится "настоящий ГГ", то
{
if (Hlp_StrCmp(npc.name,"Я"))//если у ГГ установлено имя по умолчанию, то
{
PrintScreen("Произошла загрузка игры",-1,-1,Font_ScreenSmall,10);
npc.name = " Я ";//временно изменяем имя ГГ, добавляя к нему пробелы
};
};

Wld_SendTrigger("TR_TESTEVENT");//вновь вызываем триггер, зацикливая его самого на себя
};
Триггер-скрипт будет работать постоянно, с интервалом в 1 сек., отслеживая изменения в имени ГГ и выполняя соответствующие действия, в данном случае только вывод сообщения.
Вообщем то такие триггер-скрипты надо разместить на всех отдельных локациях. И запускать их аналогичным образом.
 

alexel

Участник форума
Регистрация
28 Апр 2014
Сообщения
12
Благодарности
0
Баллы
165
У меня тогда срабатывало в двух случаях:
Забавно, вам нужен цикл триггер для проверки самой загрузки, мне же совершенно наоборот) Была идея при загрузке некоторые переменные обнулять и в цикл триггере свойство срабатывало бы один раз за загрузку. Сначала, я все сделал через init'ы, спасибо ElderGamer за подсказку, загружало нормально, никакой мороки) Потом передумал, и реализовал вообще без обнуления переменных)
 

Jr13San


Модостроитель
Регистрация
1 Апр 2010
Сообщения
449
Благодарности
266
Баллы
230
Забавно, вам нужен цикл триггер для проверки самой загрузки, мне же совершенно наоборот)
Забавно-то забавно, но как вы определите такой момент. Срабатывает INIT-функция. Игрок находится в месте появления на определённой локации.

Какими будут ваши предположения?
а) игрок только что перешёл на новую локацию.
б) он просто сохранился в месте появления на этой новой локации и вот сейчас только что загрузился.
 

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.168
Баллы
915
@Jr13San:
Т.е. в данном случае использование переменной aivar[AIV_LOADGAME] ничего не даст?
 

Jr13San


Модостроитель
Регистрация
1 Апр 2010
Сообщения
449
Благодарности
266
Баллы
230
Dimus, это смотря применительно к чему этот aivar использовать.
Например, "hero.aivar[AIV_LOADGAME]" постоянно возвращает 0.
 

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.168
Баллы
915
@Jr13San:
Хм... Тогда зачем в функциях B_ValidateOther(), ZS_Attack() и ZS_Flee() используется переменная self.aivar[AIV_LOADGAME]? Или же она не может быть применима, если указатель self даст ссылку на массив hero.aivar[]?:oops:
 
Последнее редактирование:

Jr13San


Модостроитель
Регистрация
1 Апр 2010
Сообщения
449
Благодарности
266
Баллы
230
Хм... Тогда зачем в функциях B_ValidateOther(), ZS_Attack() и ZS_Flee() используется переменная self.aivar[AIV_LOADGAME]?
Переменная как переменная. Вижу только что в функции "B_ValidateOther()" ей присваиваются значения TRUE и FALSE в определённых случаях, а в остальных функциях идёт только использование этой переменной. Dimus, Вы мне конкретный пример приведите, раз уверены, что этот aivar[AIV_LOADGAME] работает.
Цель ваших рассуждений? Может быть вы меня пытаетесь завести в тупик. Не знаю - не знаю.:oops:
 

ElderGamer


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

В Г2, например, существует запоминание текущей локации. Кто мешает ввести ещё одну переменную для запоминания "предыдущей" локации? Сравнивая значения текущей и "предыдущей" локации можно понять, был ли факт перехода из одной локации в другую, или произошла загрузка сохранения. ;)

Кстати, обращал ли кто внимание, что неписи в Готиках спят с открытыми глазами? Для Г1 решение проблемы существует. Думаю, оно вполне подойдёт и для Г2.
 
Последнее редактирование:

Dimus

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

Jr13San


Модостроитель
Регистрация
1 Апр 2010
Сообщения
449
Благодарности
266
Баллы
230
Я никого не стараюсь завести в тупик, т.к. мне самому хочется знать, зачем в скриптах задействовано это условие.
Это хорошо.:)

В Г2, например, существует запоминание текущей локации. Кто мешает ввести ещё одну переменную для запоминания "предыдущей" локации? Сравнивая значения текущей и "предыдущей" локации можно понять, был ли факт перехода из одной локации в другую, или произошла загрузка сохранения.
Ну допустим. Дело то это не меняет.
Например, ГГ перешёл из OLDWORLD.ZEN на NEWWORLD.ZEN. После перехода, сразу же сохранился. Загрузился. ElderGamer, Ваши предположения?
 

ElderGamer


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

С точки зрения скриптов нет ни какой разницы, сохранился ли игрок сразу же после перехода в новую локацию, или после перехода играл в ней пару часов. Функция инициализации локации будет выполнена ДО того, как игрок получит возможность сохраниться.
 

Jr13San


Модостроитель
Регистрация
1 Апр 2010
Сообщения
449
Благодарности
266
Баллы
230
Функция инициализации локации будет выполнена ДО того, как игрок получит возможность сохраниться.
Ну хорошо, а вы можете привести код для нескольких локаций? Ну, чтобы не быть голословным.
Для примера можно взять: WORLD1, WORLD2, WORLD3, WORLD4, WORLD5.
Стартовый - WORLD1. Переходить можно с любого на любой.
Потому что на словах одно, а на деле может быть сооовсем другое.;)
За ранее благодарен!
 
Последнее редактирование:

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

Участник форума
Регистрация
6 Дек 2012
Сообщения
350
Благодарности
521
Баллы
325
Ну, например, так (пардон, что встреваю):
В константах constants.d объявляем:
Код:
ZEN_WORLD1 = 1;
ZEN_WORLD2 = 2;
ZEN_WORLD3 = 3;
ZEN_WORLD4 = 4;
ZEN_WORLD5 = 5;
Где-нибудь до стартапа, или прямо в начале Startup.d
Код:
// запомнить, в какой локации сейчас находимся
//NewLevel - номер локи, которая сейчас загружается
func void B_SetCurrentLevel(var int NewLevel)
{
  if (CurrentLevel == 0)
  {
    //еще ничего не записывали в CurrentWorld  => новая игра
  }
  else if (CurrentLevel == NewLevel)
  {
    // загружен тот же мир, что и был => загрузка игры
  }
  else
  {
    //перешли из локации CurrentLevel в NewLevel
  };
  CurrentLevel = NewLevel;
};
И для каждой локации в Startup.d по аналогии
Код:
func void init_WORLD1()
{
    B_SetCurrentLevel(ZEN_WORLD1);
    //...
    B_InitMonsterAttitudes();
    B_InitGuildAttitudes();
    B_InitNpcGlobals();
};
Какой мир загружается первым, в общем-то, неважно.

С именем ГГ интересный способ, но эту проверку можно и не из цикл-триггера вызвать, а из тех же init_WORLD. Особенно, если ожидание триггера в целую секунду может быть критичным.

По поводу AIV_LOADGAME - переменная не такая полезная, как хотелось бы. Она используется только для NPC, которые в момент сохранения с кем-то дрались (ZS_Attack) или от кого-то убегали (ZS_Flee). Чтобы при загрузке игры вспомнить, кто противник (из AIV_LASTTARGET), и не кричать снова фоновые фразы. Соответственно, имеет смысл только, если в момент сохранения имеется дерущийся/убегающий NPC. Для ГГ вообще никогда не используется.
 
Последнее редактирование:

Jr13San


Модостроитель
Регистрация
1 Апр 2010
Сообщения
449
Благодарности
266
Баллы
230
НастасьСанна, я конечно понимаю, что написано "в торопях", но всё же, уточните пожалуйста.

У Вас не написано где присваиваются значения переменной "CurrentLevel". Остаётся принять её во внимание из оригинальных скриптов.
К тому же названия функций разнятся: "B_SetWordl" и "B_SetCurrentLevel". Вы уж поправьте.
 
Сверху Снизу