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

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

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

MaGoth

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

Вложения

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

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.000
Благодарности
968
Баллы
295
а есть какое то решение типа зелья подводного дыхания? :)
 

RPD

Участник форума
Регистрация
13 Ноя 2023
Сообщения
118
Благодарности
3
Баллы
40
День добрый! Сделал кастомную дубинку с интересной особенностью: Она имеет огромный урон в 480 единиу, но при этом реализовать его во всю не получится, так как она накидывает огромный дебаф в 10% от МАКСИМАЛЬНОГО владения двуручным оружием и в -50 к силе. То есть использовать ее можно при уже 120 силы, но во время использования будет 70. (По моей задумке она будет играться из-за шанса критов различного уровня силы с разными шансами. То есть кастомные криты будут в приоритете, а не обыкновенные) Сложнее было придумать логику как раз вот этого отсчета 10% от владения двуручкой. Я пришел к посредственному, как по мне, временному решению, код кину ниже.
Daedalus:
func void equip_2h_bogdan_stick()
{
    self.aivar[Full_2H] = self.HitChance[NPC_TALENT_2H];
    self.attribute[ATR_STRENGTH] = self.attribute[ATR_STRENGTH] - 50;
    self.HitChance[NPC_TALENT_2H] = MathFloor(self.HitChance[NPC_TALENT_2H])/10;
    B_AddFightSkill(self,NPC_TALENT_2H,0);
   
    //B_AddFightSkill(self,NPC_TALENT_2H,-(((self.HitChance[NPC_TALENT_2H])*90)/100));
};

func void unequip_2h_bogdan_stick()
{
    self.attribute[ATR_STRENGTH] = self.attribute[ATR_STRENGTH] + 50;
    self.HitChance[NPC_TALENT_2H] = self.aivar[Full_2H];
    B_AddFightSkill(self,NPC_TALENT_2H,0);
   
    //B_AddFightSkill(self,NPC_TALENT_2H,+((self.HitChance[NPC_TALENT_2H])*9));
};

Проблема в том, что вот эти вот владения оружием, сила, ловкость используют int тип данных, а не float. А также, как я понимаю, нету возможности поделить число и получить из него другое, с плавающей точкой. По итогу я решил просто написать функцию округления МАКСИМАЛЬНОГО владения двуручкой в большую или меньшую сторону, в зависимости от последней цифры в числе. Эта тема меня, впринципе, устраивает. ТО, что не нравится, это сохранение максимального уровня владения в отдельном аивере, так как после округления я не могу воссоздать прошлое число. А не нравится потому что кажется, что придется дописывать переопределение этого максимального уровня владения в функциях использования разных других обвесов, по типу поясов или чего-то там на двуручку. Буду благодарен, если предложите вариант полегче и практичнее)

Daedalus:
func int MathFloor(var int num)
{
    var int rem; rem = num % 10;
   
    if(rem >= 5)
    {
        return ((num - (num % 10)) + 10);
    };
   
    return (num - (num % 10));
};
 

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.000
Благодарности
968
Баллы
295
МАКСИМАЛЬНОГО
максимальный это 100. ты наверное говоришь про реальный уровень.

ТО, что не нравится, это сохранение максимального уровня владения в отдельном аивере, так как после округления я не могу воссоздать прошлое число
пираньи тоже записывали реальные показатели НПС в отдельный аивер. впрочем если эту дубину будет использовать герой, то можно записывать не в аивер а просто в переменную.

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

RPD

Участник форума
Регистрация
13 Ноя 2023
Сообщения
118
Благодарности
3
Баллы
40
максимальный это 100. ты наверное говоришь про реальный уровень.
пираньи тоже записывали реальные показатели НПС в отдельный аивер. впрочем если эту дубину будет использовать герой, то можно записывать не в аивер а просто в переменную.
Да, я знаю, что есть аиверы real_talent, real_strength. Но разве они в себя не включают именно только прокачанные единицы за очки? Просто я вижу это так, что ежели у меня допустим будет 76% за очки, без баффов. После надевания дубинки становится после округления 8%. Обратно же, если снять, возвращается значение владения, которое было на момент вызова функции экипировки. А вот если я с надетой дубиной надену, к примеру, еще какой нибудь пояс на +10% к владению двуручкой (если бы он был). То получается, что без переопределения именно максимального значения (именно и за очки и + бонусы с обвесов), оно просто приплюсуется к этим 8% и будет 18% - а это уже совсем все ломает. Как я понимаю, обязательно приходится переопределять, ведь я же беру 10% от общего, максимального, всего объема (опять же и бонусы, и прокачанные за очки навыки двуручки).

Ну и да, максимальный уровень владения двуручкой с надетой дубинкой не будет превышать 10%. Тут вопрос в том, что эти микробаффы от, например, пояса на +10 или кольца на +5 к двуручке все равно могут сказаться. Например, было у меня 64% ,без баффов, без всего. С надетой дубиной это 6% после окргуления в меньшую сторону. А добавь к этим 64 кольцо на +5 и тогда уже будет округляться к 7%. Вот в чем идея
 

Beowulf

Участник форума
Регистрация
21 Ноя 2010
Сообщения
1.940
Благодарности
1.454
Баллы
465
MW 7, на Юне не знаю, а вот на уровне стандартных скриптов посмотри мод Яктиль - там то ли зелье, то ли растение.
 

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.000
Благодарности
968
Баллы
295
ну это всё понятно. поэтому я написал что если дубина одна то это проще сделать через OnDamage_Hit . если говорить про реализацию на оригинальных скриптах то тогда там нужно "врезаться" в B_AddFightSkill и там делать проверку на то одета ли дубина и если она одета куда то перезаписывать истинное значение навыка, рассчитывать штрафное значение навыка и обновлять значение навыка.
 

RPD

Участник форума
Регистрация
13 Ноя 2023
Сообщения
118
Благодарности
3
Баллы
40
ну это всё понятно. поэтому я написал что если дубина одна то это проще сделать через OnDamage_Hit . если говорить про реализацию на оригинальных скриптах то тогда там нужно "врезаться" в B_AddFightSkill и там делать проверку на то одета ли дубина и если она одета куда то перезаписывать истинное значение навыка, рассчитывать штрафное значение навыка и обновлять значение навыка.
Спасибо, через оndamage попробую.

Еще хотел бы поинтересоваться, все ли более менее структурно правильно расположено и не забыл ли я чего важного вставить.
Daedalus:
func void ZS_Unconscious_SC()
{
    other = Hlp_GetNpc(self.aivar[AIV_LASTTARGET]);
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    if(self.bodyStateInterruptableOverride == false)
    {
        self.bodyStateInterruptableOverride = true;
    };
    if(C_BodyStateContains(self,BS_SWIM) || C_BodyStateContains(self,BS_DIVE))
    {
        Npc_ClearAIQueue(self);
        B_ClearPerceptions(self);
        AI_StartState(self,ZS_Dead,0,"");
        return;
    };
    Npc_SetTempAttitude(self,ATT_HOSTILE);
    Npc_SetRefuseTalk(self,0);
    B_StopLookAt(self);
    AI_StopPointAt(self);
    AI_PlayAni(self,"T_DEAD");
};

func int ZS_Unconscious_SC_Loop()
{
    if(Npc_GetStateTime(self) < 5)
    {
        return LOOP_CONTINUE;
    }
    else
    {
        return LOOP_END;
    };
};

func void ZS_Unconscious_SC_End()
{
    AI_StandUp(self);
    if(Npc_IsPlayer(self))
    {
        return;
    };
    Npc_PerceiveAll(self);
    if(self.guild < GIL_SEPERATOR_HUM)
    {
        B_Attack(self,other,AR_NONE,0);
    }
    else
    {
        AI_StartState(self,ZS_MM_Attack,0,"");
    };
};

Это уникально состояние, в которое я погружаю жертву при самом сильном срабатывании крита, когда, по моей задумке, непися должно сбивать с ног на 5 секунд условно, мне ничего лучше в голову не пришло, чем сделать так. Что меня беспокоит: анимациюпадения назад на спину так и не смог найти (которая срабатывает при смерти в бою), пока заменил на обычную анимацию смерти, где непись медленно ложится. Потом, не совсем понимаю,оставлять ли perceiveAll в конце цикла. Мне нужно, чтобы непись после крита через пять секунд сразу вскакивал на ноги и атаковал своего последнего обидчика.
Пост автоматически объединён:

Спасибо, через оndamage попробую.

Еще хотел бы поинтересоваться, все ли более менее структурно правильно расположено и не забыл ли я чего важного вставить.
Daedalus:
func void ZS_Unconscious_SC()
{
    other = Hlp_GetNpc(self.aivar[AIV_LASTTARGET]);
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    if(self.bodyStateInterruptableOverride == false)
    {
        self.bodyStateInterruptableOverride = true;
    };
    if(C_BodyStateContains(self,BS_SWIM) || C_BodyStateContains(self,BS_DIVE))
    {
        Npc_ClearAIQueue(self);
        B_ClearPerceptions(self);
        AI_StartState(self,ZS_Dead,0,"");
        return;
    };
    Npc_SetTempAttitude(self,ATT_HOSTILE);
    Npc_SetRefuseTalk(self,0);
    B_StopLookAt(self);
    AI_StopPointAt(self);
    AI_PlayAni(self,"T_DEAD");
};

func int ZS_Unconscious_SC_Loop()
{
    if(Npc_GetStateTime(self) < 5)
    {
        return LOOP_CONTINUE;
    }
    else
    {
        return LOOP_END;
    };
};

func void ZS_Unconscious_SC_End()
{
    AI_StandUp(self);
    if(Npc_IsPlayer(self))
    {
        return;
    };
    Npc_PerceiveAll(self);
    if(self.guild < GIL_SEPERATOR_HUM)
    {
        B_Attack(self,other,AR_NONE,0);
    }
    else
    {
        AI_StartState(self,ZS_MM_Attack,0,"");
    };
};

Это уникально состояние, в которое я погружаю жертву при самом сильном срабатывании крита, когда, по моей задумке, непися должно сбивать с ног на 5 секунд условно, мне ничего лучше в голову не пришло, чем сделать так. Что меня беспокоит: анимациюпадения назад на спину так и не смог найти (которая срабатывает при смерти в бою), пока заменил на обычную анимацию смерти, где непись медленно ложится. Потом, не совсем понимаю,оставлять ли perceiveAll в конце цикла. Мне нужно, чтобы непись после крита через пять секунд сразу вскакивал на ноги и атаковал своего последнего обидчика.

Daedalus:
func int C_IsItemBogdansStick(var C_Item Weap)
{
    if(Hlp_IsItem(Weap,ItMw_2H_BogdanStick) == TRUE)
    {
        return TRUE;
    };
    return FALSE;
};

func int C_HasReadiedBogdansStick(var C_NPC slf)
{
    var C_Item ReadyWeap;
    ReadyWeap = Npc_GetReadiedWeapon(slf);
    if(C_IsItemBogdansStick(ReadyWeap))
    {
        return TRUE;
    };
    return FALSE;
};

func void B_Random_StanCrit(var C_NPC slf,var C_NPC oth)
{
    if(C_HasReadiedBogdansStick(oth) == true)
    {  
        var int random; random = Hlp_Random(100);
       
        if(random <= 10)
        {  
            Wld_PlayEffect("",slf,slf,1,800,DAM_BLUNT,FALSE);
            AI_StartState(slf,ZS_Unconscious_SC,0,"");
            PrintScreen("Сильнейший крит!!!",0,-1,"FONT_OLD_20_WHITE.TGA",1);
        }
        else if(random > 10 && random <= 25)
        {
            Wld_PlayEffect("",slf,slf,1,400,DAM_BLUNT,FALSE);
            PrintScreen("Хороший крит!!",-1,-1,"FONT_OLD_20_WHITE.TGA",1);
        }
        else if(random > 25 && random <= 45)
        {
            Wld_PlayEffect("",slf,slf,1,200,DAM_BLUNT,FALSE);
            PrintScreen("Крит!",1,-1,"FONT_OLD_20_WHITE.TGA",1);
        };
    };
};

И еще как будто бы не срабатывает урон после крита. Может дело в отсутствии эффекта в скобках? Вроде ж необязателен, не?
 

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.000
Благодарности
968
Баллы
295
если говорить про реализацию на оригинальных скриптах то тогда там нужно "врезаться" в B_AddFightSkill и там делать проверку на то одета ли дубина и если она одета куда то перезаписывать истинное значение навыка, рассчитывать штрафное значение навыка и обновлять значение навыка.
Daedalus:
var int BogdanStick;
var int BogdanStick_Full_2H;

func void equip_2h_bogdan_stick()
{
    BogdanStick = 1;
    self.attribute[ATR_STRENGTH] -=  50;
    B_AddFightSkill(self,NPC_TALENT_2H,0);
};

func void unequip_2h_bogdan_stick()
{
    BogdanStick = 3;
    self.attribute[ATR_STRENGTH] +=  50;
    B_AddFightSkill(self,NPC_TALENT_2H,0);
};


func void B_AddFightSkill (var C_NPC slf, var int talent, var int percent)
{
    if BogdanStick == 1 // герой одевает дубину
    {
        BogdanStick_Full_2H = slf.HitChance[NPC_TALENT_2H];
        slf.HitChance[NPC_TALENT_2H] = MathFloor(BogdanStick_Full_2H)/10; // херня какая то. лучше перепроверить
        Npc_SetTalentSkill (slf, NPC_TALENT_2H, 0);
        BogdanStick = 2;
        return;
    };
    
    if BogdanStick == 2 // дубина уже одета
    {
        BogdanStick_Full_2H += percent;
        slf.HitChance[NPC_TALENT_2H] = MathFloor(BogdanStick_Full_2H)/10; // херня какая то. лучше перепроверить
        Npc_SetTalentSkill (slf, NPC_TALENT_2H, 0);
        return;
    };

    if (BogdanStick == 3) // дубина снаята
    {
        slf.HitChance[NPC_TALENT_2H] = BogdanStick_Full_2H; // херня какая то. лучше перепроверить
        BogdanStick_Full_2H = 0;
        BogdanStick = 0;
    };
    // Далее оригинальный код
 

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.000
Благодарности
968
Баллы
295
еще как будто бы не срабатывает урон после крита. Может дело в отсутствии эффекта в скобках? Вроде ж необязателен, не?

необязательно. а зачем урон наносить через Wld_PlayEffect если визуального эффекта нет? просто отними жизни, если надо с учётом брони.


var int random; random = Hlp_Random(100);
добавляй 1, что бы голова не болела. то есть
Daedalus:
var int random; random = Hlp_Random(100) + 1; // от 1 до 100.

Daedalus:
        if (random > 45) // больше 45
        {
        }
        else if (random > 25) // от 25 до 45
        {
             // шанс 20%
        }
        else if (random > 10) // от 10 до 25
        {  
             // шанс 15%           
        }
        else // от 1 до 10
        {
             // шанс 10%           
        };
 
Последнее редактирование:

RPD

Участник форума
Регистрация
13 Ноя 2023
Сообщения
118
Благодарности
3
Баллы
40
необязательно. а зачем урон наносить через Wld_PlayEffect если визуального эффекта нет? просто отними жизни, если надо с учётом брони.
Вообще планировал добавить что-то вроде как у кулака ветра, но в более нежной форме. А так то да.
добавляй 1, что бы голова не болела. то есть
Daedalus:
var int random; random = Hlp_Random(100) + 1; // от 1 до 100.
оно разве не сразу считает random, то есть эта единца дает такой эффект?
можно проверки на рандом перевернуть
Daedalus:
        if (random > 45) // больше 45
        {
        }
        else if (random > 25) // от 25 до 45
        {
             // шанс 20%
        }
        else if (random > 10) // от 10 до 25
        {  
             // шанс 15%           
        }
        else // от 1 до 10
        {
             // шанс 10%           
        };

Можно, но в целом я не планировал ничего делать при 55 процентах. Как буд-то бы просто пустые удары
 

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.000
Благодарности
968
Баллы
295
оно разве не сразу считает random, то есть эта единца дает такой эффект?
добавление единички убирает 0. то есть у тебя вероятность будет от 1 до 100.

Вообще планировал добавить что-то вроде как у кулака ветра, но в более нежной форме. А так то да.
отбрасывать?
 

RPD

Участник форума
Регистрация
13 Ноя 2023
Сообщения
118
Благодарности
3
Баллы
40
добавление единички убирает 0. то есть у тебя вероятность будет от 1 до 100.


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

Oxbow

Участник форума
Регистрация
22 Дек 2017
Сообщения
265
Благодарности
33
Баллы
200
Здраствуйте,
Можете подсказать, как прописать в коде, чтобы собеседник уснул в процессе диалога?
 

Oxbow

Участник форума
Регистрация
22 Дек 2017
Сообщения
265
Благодарности
33
Баллы
200
типо
AI_StartState(self,ZS_MagicSleep,0,"");
Ладно попробую спасибо.
А еще подскажите в игре есть проверка на обыскивание ГГ трупа НПС (типо диалог появляется только после того, как ГГ обыщет труп НПС)?
 

MEG@VOLT

★★★★★★★★★
ТехАдмин
Регистрация
24 Мар 2006
Сообщения
9.860
Благодарности
6.740
Баллы
1.625

Дикарь

★★★★★★★
Модератор
Регистрация
17 Апр 2007
Сообщения
7.281
Благодарности
9.049
Баллы
1.415
диалог появляется только после того, как ГГ обыщет труп НПС)?
Я со скриптами мало ковырялся и всё забыл, так что могу ошибаться. Но, насколько понимаю, это без проблем можно сделать через проверку наличия у ГГ определённого уникального предмета, который он может забрать при обыске НПС. Взял предмет - запустился диалог.
 

ElderGamer


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

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

Silvwork

Участник форума
Регистрация
14 Мар 2015
Сообщения
168
Благодарности
1
Баллы
180
Может кто нибудь подсказать как изменить получаемый с монстров опыт?
Я полистал gothic.dat что-то не нашел ничего похожего (Поиск по ключевым словам тоже ничего не дал)
 

D36


Модостроитель
Регистрация
3 Дек 2014
Сообщения
2.189
Благодарности
3.371
Баллы
485
Может кто нибудь подсказать как изменить получаемый с монстров опыт?
Я полистал gothic.dat что-то не нашел ничего похожего (Поиск по ключевым словам тоже ничего не дал)
Формула: уровень монстра умножить на XP_PER_VICTORY (см. B_GiveDeathXP или B_GivePlayerXP в ZS_Dead). Можешь менять индивидуальные уровни монстров или общую константу XP_PER_VICTORY (10 по умолчанию).
 
Последнее редактирование:
Сверху Снизу