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

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

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

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
Для Gothic 3 - только хардкор в виде декомпиляции DLL в ассемблерный код и реверс-инжиниринга. Для упрощения работы попробуй неофициальный Gothic 3 SDK.
Этот неофициальный Gothic 3 SDK предназначен для моддеров с опытом работы на C ++ и реверс-инжиниринга.

Игровой движок Gothic 3 (Genome) состоит из нескольких библиотек динамических связей (DLL), которые являются взаимозависимыми. Поэтому каждая из этих DLL экспортирует большую часть своей функциональности. Мы можем восстановить объявления классов и функций C ++ из экспортированных символов, которые мы затем используем для взаимодействия с движком.


Двоичная совместимость

Gothic 3 была создана с помощью Visual Studio 2005 (набор инструментов платформы v80). Для оптимальной совместимости мы должны использовать один и тот же компилятор для нашего проекта. Цитирование документации MSVC по двоичной совместимости:

В Visual Studio 2013 и более ранних версиях не гарантировалась двоичная совместимость между объектными файлами (OBJ), статическими библиотеками (LIB), динамическими библиотеками (DLL) и исполняемыми файлами (EXE), созданными с помощью различных версий инструментария компилятора и библиотек времени выполнения.

Но давайте посмотрим правде в глаза, никто не хочет работать с Visual Studio 2005 в наши дни. После обширного тестирования я пришел к выводу, что Visual Studio 2013 (набор инструментов платформы v120), хотя это и не гарантировано официально, по всей видимости, двоично совместим с компилятором v80, по крайней мере, в областях, имеющих отношение к данному проекту. Использование компилятора v120 дает преимущество в виде улучшенной IDE и возможности использования функций языка C ++ 11.

Возможно, даже более новые версии Visual Studio (компилятор MSVC) будут работать, но я не тестировал это подробно.


Сборка

Gothic 3 SDK создан с помощью Visual Studio 2013 (достаточно Community Edition). В качестве альтернативы можно использовать более новую версию Visual Studio, но при этом у вас должен быть установлен набор инструментов платформы v120, который поставляется с Visual Studio 2013 (справочную информацию см. в разделе "Двоичная совместимость").

В разделе source/Scripts/ вы найдете несколько примеров проектов. Вы также можете добавить сюда свои собственные творения. Артефакты сборки попадают в bin/scripts/.


Установка

Скопируйте содержимое bin в каталог установки Gothic 3. Любая DLL в папке скриптов, которая следует соглашению об именовании Script _ *. Dll будет загружена игрой автоматически.
 

MEG@VOLT

★★★★★★★★★
ТехАдмин
Регистрация
24 Мар 2006
Сообщения
9.840
Благодарности
6.725
Баллы
1.625
Dimus, т.е. я зря гоню на человека и скрипты реально запакованы в эту dll, а не в pak файлах ?
 

KirTheSeeker

Участник форума
Регистрация
18 Авг 2017
Сообщения
1.925
Благодарности
556
Баллы
275
Приветствую всех.
А список возможных "рутин" всё ещё не расширился с данного гайда?
Т.е. есть/пить сидя они всё ещё не умеют?
 

Beowulf

Участник форума
Регистрация
21 Ноя 2010
Сообщения
1.931
Благодарности
1.441
Баллы
465
А список возможных "рутин" всё ещё не расширился с данного гайда?
Т.е. есть/пить сидя они всё ещё не умеют?
Что значит "все еще"?! Смотри модификации/базы ресурсов здесь либо на немецком воге - мб кто-то в единичных случаях, либо для своих проектов и делал по парочке распорядков дня. Ну или прописать новый распорядок дня самому для нового моб-объекта :) (взятого все с той же базы данных модостроителей)
 

Oxbow

Участник форума
Регистрация
22 Дек 2017
Сообщения
265
Благодарности
33
Баллы
200
*blush* Что значит "все еще"?! Смотри модификации/базы ресурсов здесь либо на немецком воге - мб кто-то в единичных случаях, либо для своих проектов и делал по парочке распорядков дня. Ну или прописать новый распорядок дня самому для нового моб-объекта :) (взятого все с той же базы данных модостроителей)
А можно прямую ссылочку на базу с анимациями на Воге, чтобы не тратить кучу времени на блуждания по сайту и в немецком языке?*blush*
 

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.101
Благодарности
5.592
Баллы
910
А можно прямую ссылочку на базу с анимациями на Воге, чтобы не тратить кучу времени на блуждания по сайту и в немецком языке?*blush*
Было бы что блуждать
нужно найти форум по вселенной готики
Потом вкладка Modderdatenbank (База модостроителей) - там уже интересующие вкладка Anamation (Анимации)
World of Gothic - Home
 

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.167
Баллы
915
MEG@VOLT, смотря что считать скриптами. Файлы, отвечающие за диалоги (т.н. инфоскрипты) находятся в паках, а почти вся скриптовая кухня движка зашита в dll файлах.
 

KirTheSeeker

Участник форума
Регистрация
18 Авг 2017
Сообщения
1.925
Благодарности
556
Баллы
275
Приветствую всех.
Подскажите, пожалуйста, а есть ли на форуме или ещё где тутор/гайд по созданию и вставке в игру новых документов/книг и т.п.?
 

WoOliN

Участник форума
Регистрация
13 Окт 2012
Сообщения
347
Благодарности
196
Баллы
210
Копированием и редактированием имеющихся делай, там элементарно все.

На примере стенда с книгой:
var int Animals_1_permanent; // переменная для опыта за прочтение книги

func void Use_BookstandAnimals1_S1()
{
var C_Npc her;
var int nDocID;
her = Hlp_GetNpc(PC_Hero);
if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(her)) // НПЦ-читателем установлен только ГГ
{
nDocID = Doc_Create(); // создание нового документа (переменная задана выше)
Doc_SetPages(nDocID,2); // установка количества отображаемых страниц для документа на 2
Doc_SetPage(nDocID,0,"Book_Brown_L.tga",0); // устанавливает параметры первой страницы документа: файл для изображения страницы и без масштабирования
Doc_SetPage(nDocID,1,"Book_Brown_R.tga",0); // аналогично для второй страницы
Doc_SetMargins(nDocID,0,275,20,30,20,1); // устанавливает границы вывода текста на странице, в данном случае нулевой (то есть первой) страницы, затем установлены левая, верхняя, правая и нижняя границы вывода текста и количество пикселей
Doc_SetFont(nDocID,0,FONT_BookHeadline); // установлен шрифт для идущего далее текста, в данном случае это крупный шрифт заголовка
Doc_PrintLine(nDocID,0,"Травоядные"); // вывод текста, в данном случае без переноса строки (Line)
Doc_SetFont(nDocID,0,FONT_Book); // задает другой шрифт для дальнейшего текста, в данном случае только на нулевой (первой) странице; Doc_SetFont(nDocID,-1,FONT_Book); - в таком виде задаст дальнейший шрифт для текста на всех страницах
Doc_PrintLine(nDocID,0,""); // пустая строка
Doc_PrintLines(nDocID,0,"Полезно знать, что Вепри спят с 20 часов вечера до 8 утра."); // вывод текста с переносом строки (Lines)
Doc_PrintLine(nDocID,0,"");
... // удалил остальные строки, они аналогичны
Doc_SetMargins(nDocID,-1,30,20,275,20,1); // задает границы для следующей страницы
Doc_SetFont(nDocID,1,FONT_BookHeadline); // аналогично нулевой странице, но 1 обозначает вывод информации на второй странице
Doc_PrintLine(nDocID,1,"Вепрь");
Doc_SetFont(nDocID,1,FONT_Book);
Doc_PrintLine(nDocID,1,"");
Doc_PrintLines(nDocID,1,"Вепри, несмотря на свои размеры - это чрезвычайно сильные и быстрые животные.");
... // удалил остальные строки, они аналогичны
Doc_Show(nDocID); // показывает на экране созданный документ
if(Animals_1_permanent == FALSE) // дает однократный опыт за прочтение с фразой-комментарием от ГГ, переменная задана в самом верху
{
B_Say_Overlay(self,self,"$VERSTEHE");
B_GivePlayerXP(10);
Animals_1_permanent = TRUE;
};
PrintScreen("Полезная информация!",-1,10,"FONT_OLD_20_WHITE_HI.TGA",4); // вывод отдельной доп.строки с текстовой информацией над отображаемой книгой, если это нужно
};
};
 

Beowulf

Участник форума
Регистрация
21 Ноя 2010
Сообщения
1.931
Благодарности
1.441
Баллы
465
Приветствую всех.
Подскажите, пожалуйста, а есть ли на форуме или ещё где тутор/гайд по созданию и вставке в игру новых документов/книг и т.п.?
Нет. И на каждую штуку уроков точно не будет - там даются необходимые основы для понимания скриптов. В остальном - изучаем, как что-то реализовано в оригинальной игре ;)
 

KirTheSeeker

Участник форума
Регистрация
18 Авг 2017
Сообщения
1.925
Благодарности
556
Баллы
275
Приветствую всех, вопрос по скриптам неоф. обновления.
В файле B_GiveInvItems можно найти данную функцию:
Daedalus:
func void B_GiveArmor(var int itemInstance)
{
    CreateInvItem(hero,itemInstance);
    Npc_GetInvItem(hero,itemInstance);
    AI_PrintScreen(ConcatStrings(item.description,PRINT_ItemTaken),-1,YPOS_ItemTaken,FONT_ScreenSmall,2);
};
Насколько я могу судить, она отвечает за передачу ГГ брони от NPC, с мгновенной заменой текущей брони на подаренную.
Возникают вопросы:
- Как можно создать аналогичную функцию, которая будет запускаться только когда на ГГ надета определенная броня, и не только менять текущую на новую, но и удалять прошлую броню из инвентаря?
- Можно ли прописать срабатывание новой функции не при диалоге, а во время молитвы у алтаря, добавив какую-либо анимацию, типа как при лечении?
 

WoOliN

Участник форума
Регистрация
13 Окт 2012
Сообщения
347
Благодарности
196
Баллы
210
Не за саму передачу, а за создание брони в инвентаре героя, минуя передачу брони от НПЦ ... скорее всего, чтобы НПЦ не отдавал собственную надетую броню.
Хотя и сама передача вроде работает по тому же принципу - предмет удаляется у отдающего, если там есть такой, и с нуля создается в инвентаре принимающего, просто с сопутствующими текстовыми сообщениями.

Функция по твоему запросу достаточно простая, часто используется для всяких улучшений доспехов и тому подобного.
Возьми для примера то же освящение меча паладина в файле
PrayShrine.d
плюс возьми кусок кода из функции одевания Глаза Инноса, если хочешь добавить анимации,
ну и чуть подшамань, добавив функцию для одевания конкретных доспехов (такая часто есть при выдаче доспехов гильдии, во время вступления в гильдию).

Если сильно сложно искать кусок кода для одевания конкретной брони, то нечто вроде этого:
CreateInvItem(hero,ITAR_Mil_L); // создает в инвентаре ГГ броню
AI_EquipArmor(hero,ITAR_Mil_L); // одевает на ГГ именно эту броню
 
Последнее редактирование:

KirTheSeeker

Участник форума
Регистрация
18 Авг 2017
Сообщения
1.925
Благодарности
556
Баллы
275
Приветствую всех вновь. Прошу совета по прошлому своему вопросу.
Задача такая:
- Играя за паладина и добравшись до подвалов монастыря, ГГ находит там НЕ готовые и блестящие паладинские латы, а комплект древних ржавых доспехов теневого воина (я так понял данный момент, исходя из журнала Ксардаса).
- Чтобы сделать новообретённый комплект достойным Избранного, необходимо помолиться в данном ржавом доспехе у монастырского алтаря, и доспех заменяется на свежий паладинский (с доп-м свечением, которое уже есть, и эффектом, который я ещё не придумал).
Возьми для примера то же освящение меча паладина в файле
PrayShrine.d
По аналогии с мечом сделал вот так:
Daedalus:
instance PC_PrayShrine_BlessArmor(C_Info)
{
    npc = PC_Hero;
    nr = 2;
    condition = PC_PrayShrine_BlessArmor_Condition;
    information = PC_PrayShrine_BlessArmor_Info;
    permanent = TRUE;
    description = ConcatStrings("Освятить старый доспех паладина");
};

func int PC_PrayShrine_BlessArmor_Condition()
{
    if((PLAYER_MOBSI_PRODUCTION == MOBSI_PrayShrine) && (hero.guild == GIL_PAL) && (CurrentLevel == NEWWORLD_ZEN) && (PAL_KnowsAbout_FINAL_BLESSING == TRUE) && (Npc_HasItems(hero,ITAR_PAL_Skel)))
    {
        if(Npc_GetDistToWP(hero,"NW_MONASTERY_CHAPELL_02") <= 500)
        {
            return TRUE;
        };
    };
};

func void PC_PrayShrine_BlessArmor_Info()
{
    if(ShrineIsObsessed == TRUE)
    {
        SC_IsObsessed = TRUE;
        PrintScreen(PRINT_SCIsObsessed,-1,-1,FONT_Screen,2);
        Snd_Play("DEM_Die");
    }
    else if(Npc_HasItems(hero,ITAR_PAL_Skel))
    {
        if(Npc_HasItems(hero,ITAR_PAL_Skel))
        {
            Npc_RemoveInvItems(hero,ITAR_PAL_Skel,1);
            AI_EquipArmor(hero,ITAR_PAL_BEST);
        };
        Wld_PlayEffect("spellFX_PalHeal_ORIGIN",hero,hero,0,0,0,FALSE);
        Snd_Play("MFX_Heal_Cast");
        B_GivePlayerXP(XP_SwordBlessed2);
    };
};

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

Beowulf

Участник форума
Регистрация
21 Ноя 2010
Сообщения
1.931
Благодарности
1.441
Баллы
465
KirTheSeeker, в func void PC_PrayShrine_BlessArmor_Info() пишешь
Daedalus:
var C_Item heroArmor;
heroArmor = Npc_GetEquippedArmor(other);
//... Все, что было в оригинальном скрипте...
else (Hlp_IsItem(heroArmor,ITAR_PAL_Skel) == TRUE)
   {
        //Прописывай то, что должно происходить в случае, если гг одет в ржавый доспех
   };
 

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.992
Благодарности
967
Баллы
275
Daedalus:
/*
INSTANCE ITAR_PAL_BEST(C_Item)
{
    ITAR_PAL_H();
};
*/

// функция проверяет надет ли на НПС конкретный доспех
func int C_NpcEquippedArmor(var c_npc npc, var int itar)
{
    if Npc_HasEquippedArmor(npc) == FALSE   // на НПС нет брони
    {
        return FALSE;
    };
  
    var C_ITEM itm; itm = Npc_GetEquippedArmor(npc);
    if (Hlp_IsItem (itm, itar) == TRUE)
    {
        return TRUE;  
    };
  
    return FALSE;
};


const int     XP_PalArmorBlessed = 666;      // сколько герой получит опыта за успешную молитву?

instance PC_PrayShrine_BlessArmor(C_Info)
{
    npc = PC_Hero;
    nr = 2;
    condition = PC_PrayShrine_BlessArmor_Condition;
    information = PC_PrayShrine_BlessArmor_Info;
    permanent = TRUE;                               // один раз освятить можно или много раз?
    description = "Освятить старый доспех паладина";
};

func int PC_PrayShrine_BlessArmor_Condition()
{
    if (PLAYER_MOBSI_PRODUCTION != MOBSI_PrayShrine)
    {
        return FALSE;  
    };
    if (hero.guild != GIL_PAL)
    {
        return FALSE;  
    };
  
    // ГГ паладин молится Инносу
    if (CurrentLevel == NEWWORLD_ZEN)                           // Хоринос
    && (Npc_GetDistToWP(hero,"NW_MONASTERY_CHAPELL_02") <= 500) // Монастырь
    && (C_NpcEquippedArmor(hero,ITAR_PAL_Skel) == TRUE)         // на герое одет старый доспех
    {
        return TRUE;
    };
};

func void PC_PrayShrine_BlessArmor_Info()
{
    Npc_RemoveInvItems  (hero,ITAR_PAL_Skel,1);   // убирать один доспех или все?
    CreateInvItem        (hero, ITAR_PAL_BEST);  // создать доспех
    AI_EquipArmor        (hero, ITAR_PAL_BEST);    // одеть доспех
    B_GivePlayerXP(XP_PalArmorBlessed); // дать опыт
  
    // спецэффекты
    Wld_PlayEffect("spellFX_PalHeal_ORIGIN",hero,hero,0,0,0,FALSE);
    Snd_Play("MFX_Heal_Cast");
};

В скриптах можно как-то прописать рандомизатор внешности для NPC?
да.
 
Последнее редактирование:

D36


Модостроитель
Регистрация
3 Дек 2014
Сообщения
2.178
Благодарности
3.351
Баллы
485
В неофициальном обновлении есть готовая общая функция ArmorEquipped, проверяющая экипированные доспехи.
Daedalus:
instance PC_PrayShrine_BlessArmor(C_Info)
{
    npc = PC_Hero;
    nr = 4; //новый слот, чтобы не мешать другим опциям
    condition = PC_PrayShrine_BlessArmor_Condition;
    information = PC_PrayShrine_BlessArmor_Info;
    permanent = FALSE; //диалог одноразовый
    description = "Освятить старые доспехи паладина"; //правильное написание предмета
};

func int PC_PrayShrine_BlessArmor_Condition()
{
    if((PLAYER_MOBSI_PRODUCTION == MOBSI_PrayShrine) && (hero.guild == GIL_PAL) && (CurrentLevel == NEWWORLD_ZEN) && (PAL_KnowsAbout_FINAL_BLESSING == TRUE) && ArmorEquipped(hero,ITAR_PAL_Skel))
    {
        if(Npc_GetDistToWP(hero,"NW_MONASTERY_CHAPELL_02") <= 500)
        {
            return TRUE;
        };
    };
};

func void PC_PrayShrine_BlessArmor_Info()
{
    if(ShrineIsObsessed == TRUE) //алтарь в монастыре никогда не оскверняется, можно убрать этот блок
    {
        SC_IsObsessed = TRUE;
        PrintScreen(PRINT_SCIsObsessed,-1,-1,FONT_Screen,2);
        Snd_Play("DEM_Die");
    }
    else
    {
        B_RemoveEveryInvItem(hero,ITAR_PAL_Skel); //удалить все старые доспехи из инвентаря
        CreateInvItem(hero,ITAR_PAL_BEST); //создать новые доспехи
        AI_EquipArmor(hero,ITAR_PAL_BEST); //экипировать новые доспехи
        Wld_PlayEffect("spellFX_PalHeal_ORIGIN",hero,hero,0,0,0,FALSE);
        Snd_Play("MFX_Heal_Cast");
        B_GivePlayerXP(XP_SwordBlessed2); //лучше добавить новую отдельную константу с опытом
    };
};
 

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.992
Благодарности
967
Баллы
275
В моем случае это в принципе применимо, но было бы удобнее, если бы можно было брать за основу существующего npc, брать его visual и немного крутить его рандомом. Например другое тело и голову, а все остальное не важно. В таком случае рандом был бы динамический, а не ограничен пулом заготовок.
Daedalus:
//func void B_SetNpcVisual_Random(var int armorInstance)
func void B_SetNpcVisual_Random()
{
    // форма головы
    var string Hum_Head_Random;
    var int zufall; zufall = Hlp_Random(6);
    if      (zufall == 0)   { Hum_Head_Random = "Hum_Head_Psionic"; }
    else if (zufall == 1)   { Hum_Head_Random = "Hum_Head_Thief";   }
    else if (zufall == 2)   { Hum_Head_Random = "Hum_Head_Bald";    }
    else if (zufall == 3)   { Hum_Head_Random = "Hum_Head_Pony";    }
    else if (zufall == 4)   { Hum_Head_Random = "Hum_Head_Fighter"; }
    else if (zufall == 5)   { Hum_Head_Random = "Hum_Head_FatBald"; };

    // текстура лица
    var int Face_L_Random;    Face_L_Random = Hlp_Random(96) + 41;

    // текстура тела
    var int Rassen;     
    if      Face_L_Random <= 057     { Rassen = BodyTex_P; }    //Pale
    else if Face_L_Random <= 119     { Rassen = BodyTex_N; }    //Normal
    else if Face_L_Random <= 128     { Rassen = BodyTex_L; }    //Latinos
    else if Face_L_Random <= 136     { Rassen = BodyTex_B; };   //Black
 
    // armor
    var C_ITEM armor;
    if Npc_HasEquippedArmor(self) == true   // на НПС есть броня
    {
        armor = Npc_GetEquippedArmor(self);
    };
    B_SetNpcVisual(self, MALE, Hum_Head_Random, Face_L_Random,  Rassen, armor);
};
 
Последнее редактирование:

KirTheSeeker

Участник форума
Регистрация
18 Авг 2017
Сообщения
1.925
Благодарности
556
Баллы
275
В неофициальном обновлении есть готовая общая функция ArmorEquipped, проверяющая экипированные доспехи.
Daedalus:
instance PC_PrayShrine_BlessArmor(C_Info)
{
    npc = PC_Hero;
    nr = 4; //новый слот, чтобы не мешать другим опциям
    condition = PC_PrayShrine_BlessArmor_Condition;
    information = PC_PrayShrine_BlessArmor_Info;
    permanent = FALSE; //диалог одноразовый
    description = "Освятить старые доспехи паладина"; //правильное написание предмета
};

func int PC_PrayShrine_BlessArmor_Condition()
{
    if((PLAYER_MOBSI_PRODUCTION == MOBSI_PrayShrine) && (hero.guild == GIL_PAL) && (CurrentLevel == NEWWORLD_ZEN) && (PAL_KnowsAbout_FINAL_BLESSING == TRUE) && ArmorEquipped(hero,ITAR_PAL_Skel))
    {
        if(Npc_GetDistToWP(hero,"NW_MONASTERY_CHAPELL_02") <= 500)
        {
            return TRUE;
        };
    };
};

func void PC_PrayShrine_BlessArmor_Info()
{
        B_RemoveEveryInvItem(hero,ITAR_PAL_Skel); //удалить все старые доспехи из инвентаря
        CreateInvItem(hero,ITAR_PAL_BEST); //создать новые доспехи
        AI_EquipArmor(hero,ITAR_PAL_BEST); //экипировать новые доспехи
        Wld_PlayEffect("spellFX_PalHeal_ORIGIN",hero,hero,0,0,0,FALSE);
        Snd_Play("MFX_Heal_Cast");
        B_GivePlayerXP(XP_ArmorBlessed2); 
};
Да, такой вариант сработал, благодарю.

А где можно достать другую модель паладинского доспеха, с опущенным забралом?
 
Сверху Снизу