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

    Чтобы получить возможность писать на форуме, оставьте сообщение в этой теме.
    Удачи!
  • Друзья, доброго времени суток! Спешите принять участие в конкурсе "Таинственные миры" 2024!
    Ждем именно вас!

    Ссылка на конкурсную тему - тык

Инструкция OnDamage_Hit – модернизация урона [модостроение]

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.922
Благодарности
926
Баллы
275
Пока без дополнительного описания. Все будет чуть позже.

**
* написать пример магического арбалета с молнией
* написать пример лука охотника с доп. уроном по каким то зверям
* написать про какой нибудь меч который наносит доп урон ночью хз кому
* Орки делают криты в зависимости от оружия
* Топоры Орков (и не только) могут нанести крит
*крит для "тяжёлых" двуручных топоров (сила больше чем ущерб)
* посохи магов огня/воды с доп уроном по ледяным/огненным монстрам
*оружие доп ущерб по огненным или ледяным существам
* освященные "Слезами Инноса" клинки паладина "изгоняют зло"
* какой то меч против кого то там
* какое то оружие против какого то доспеха
* какое то оружие против какой то гильдии
* Уризель 2.0

*посох магии изгоняющий призванных существ


сделать примеры магиии . показать как связать уровень спела с временим эффекта.


 
Последнее редактирование:

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.922
Благодарности
926
Баллы
275
Orc Hunter, ну если чего-то сложного не надо, то вот скриптовый модификатор урона. Попробуй.

В скриптах необходимо определить функцию func int OnDamage_Hit(var int damageTotal)
Плагин автоматически вызовет скриптовую функцию и установит следующие значения:
self - атакующий
victim - атакуемый
item - орудие убийства (может быть null)

Параметры функции:
damageTotal - рассчитанное количество урона, которое предполагается снять с victim

Возвращаемое значение:
Новое значение урона, которое будет снято с victim

Примечание:
Скриптовый модификатор урона не будет вызван, если victim неуязвим.

Пример:

Daedalus:
func int OnDamage_Hit(var int damageTotal)
{
    if (Npc_IsPlayer(self) && Hlp_GetInstanceID(DJG_713_Biff_DI) == Hlp_GetInstanceID(victim))
    {
        return 10000;
    };
 
    return damageTotal;
};
 
Последнее редактирование модератором:

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.281
Благодарности
4.581
Баллы
625
Orc Hunter, там будет Null.
Расширил инфу о дамаге. Определи в скрипте структуру C_DamageInfo и производную от нее инстанцию damageinfo.
В инстанцию будет писаться дополнительная инфа:
Daedalus:
class C_DamageInfo
{
    var int ItemID;
    var int IsSpellDamage;
    var int SpellID;
    var int SpellLevel;
};

instance damageinfo(C_DamageInfo) { };

- ItemID - номер инстанции предмета, которым нанесен урон. Если предмета нет или это был спелл, то номер будет равен -1.
- IsSpellDamage - значение, определяющее, нанесен ли урон спелом.
- SpellID - идентификатор спела, например SPL_FIREBALL.
- SpellLevel - уровень спела, например при касте огненной бури.
 

Вложения

  • oDamageHelper.7z
    143,4 KB · Просмотры: 21

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.922
Благодарности
926
Баллы
275
Gratt, выложи пожалуйста последнюю версию файла :)
 

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.922
Благодарности
926
Баллы
275
Пример использования функции. Например вы хотите полностью поменять расчёт урона для рапир и шпаг.
В OnDamage_Hit производится проверка на то был ли удар нанесён Рапирой или Шпагой, после рассчитываем новый урон или возвращаем старый. Проверку и расчёт урона я для удобства вынес в отдельный файл.
Daedalus:
func int OnDamage_Hit(var int damageTotal)
{
    if (Npc_IsEquippedItMw1hRPR(item) == true)
    { 
        return  DMG_ItMw1hRPR(self, victim, item); 
    };   
    return damageTotal;
};
 

Вложения

  • ItMw1hRPR.zip
    904 байт · Просмотры: 12

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.922
Благодарности
926
Баллы
275
как определить каким оружием бы нанесён урон
итак у нас уже есть оружие item, а значит мы без затей можем провести проверку по всему что есть в классе C_Item.

damageType damageTotal cond_value cond_atr value ownerGuild ID nameID mainflag flags instance range


  • damageType - тип наносимого повреждения
    уронdamageTypeпример проверкипримечание
    "Дробящий"DAM_BLUNT
    Daedalus:
    if (item.damageType == DAM_BLUNT)
    к дробящему урону "уязвимы" некоторые монстры
    "Режущий"DAM_EDGE
    Daedalus:
    if (item.damageType ==  DAM_EDGE)
    большинство оружия имеет режущий урон
    "колющий"DAM_POINT
    Daedalus:
    if (item.damageType ==  DAM_POINT)
    тип урона у луков и арбалетов


  • damageTotal - общая величина урона
    такую проверку можно использовать для того что бы определить насколько "мощное оружие". например if (item.damageTotal >=130) мы понимаем что оружие "мощное" и можем пересчитать урон, уменьшив например влияние защиты жертвы или дав шанс нанести такому оружию дополнительный ущерб. или шанс проигнорировать защиту жертву или прикрутить какой то эффект.

  • cond_value - минимальное значение атрибута, которым должен обладать Npc для экипировки предмета (с)
    давайте условно разделим всё оружие на то у которого ущерб больше чем требуется атрибута, равен или меньше. и мы получим условно три типа: плохое, обычное и хорошее.

    условный типпример проверкипримечание
    "плохое" оружие
    Daedalus:
    if (item.cond_value[2] > item.damageTotal)
    грубые, потёртые, ржавые, старое и т.п. оружие. некоторое дробящее оружие.
    "обычное " оружие
    Daedalus:
    if (item.cond_value[2] == item.damageTotal)
    большинство оружие
    "хорошее" оружие
    Daedalus:
    if (item.cond_value[2] < item.damageTotal)
    все рудные клинки, самокованное оружие, прочее

  • cond_atr - массив атрибутов Npc необходимых для экипировки предмета (с)
    можно использовать как дополнительную проверку что бы например вычленить оружие ближнего боя требующую ловкость.[/I][/I][/I]
    атакующий НПС держит оружие ближнего боя которое требует ловкость
    Daedalus:
     if (Npc_HasReadiedMeleeWeapon(self)  
     && item.cond_atr[2] == ATR_DEXTERITY)
    это будет шпага, шпага мастера, бетти, рапира и бандитская шпага
    атакующий НПС держит оружие дальнего боя которое требует силу
    Daedalus:
    if (Npc_HasReadiedRangedWeapon(self)
    && item.cond_atr[2] == ATR_STRENGTH)
    получатся все арбалеты
    так же проверку на cond_atr можно использовать в связки с проверкой по флагу и/или главному флагу, результат в 99 случаев из 100 будет такой же :)

  • value - стоимость предмета (с) в классе C_Item.
    цена предмета не всегда отображает его св-ва. впрочем вы можете использовать проверку на цену с сочетанием с реакцией на удар. например если нпс1 бьет нпс2 дорогим клинком, то НПС2 может дать какой то комментарий относительно того что он сделает с этим оружием после победы:)


  • ownerGuild -какой гильдии принадлежит предмет(с). в классе C_Item.
    Проверка на гильдию которой принадлежит предмет прекрасна, к сожалению в оригинальной игре это не используется, но если вы делаете мод то может назначить некоторым оружиям гильдию паладинов и через такую проверку определить такое оружие.

  • id - так же не используется в игре, но прекрасно подойдёт для модов: так легко создать некий класс оружия назначив им общий айди. так же можно использовать для какого то оружия с большим кол-вом инстанций, например Коготь Белиара.

  • nameID
    Проверка по nameID так же можно использовать в модах
    if(Hlp_StrCmp(EquippedWeapon.nameID,"Unique Item"))

  • mainflag - категории предметов (с)
    оружие ближнего бояITEM_KAT_NFif (item.mainflag & ITEM_KAT_NF)
    оружие дальнего бояITEM_KAT_FFif (item.mainflag & ITEM_KAT_FF)

    Используем проверку на mainflag например с проверкой на cond_atr

    оружие ближнего боя которое требует ловкостьif (item.mainflag & ITEM_KAT_NF)
    && item.cond_atr[2] == ATR_DEXTERITY)
    это будет шпага, шпага мастера, бетти, рапира и бандитская шпага
    оружие дальнего боя которое требует силу
    if (item.mainflag & ITEM_KAT_FF)
    && item.cond_atr[2] == ATR_STRENGTH)
    получатся все арбалеты

  • flags -Тип предмета и его свойства (с)
    в случае с оружием это флаги для 1р, 2р , луков и арбалетов
    оружие ближнего бояITEM_SWDif (item.flags & ITEM_SWD)
    оружие дальнего бояITEM_AXEif (item.flags & ITEM_AXE)
    Двуручный мечITEM_2HD_SWDif (item.flags & ITEM_2HD_SWD)
    Двуручный топорITEM_2HD_AXEif (item.flags & ITEM_2HD_AXE)
    ЩитITEM_SHIELDif (item.flags & ITEM_SHIELD)
    ЛукITEM_BOWif (item.flags & ITEM_BOW)
    АрбалетITEM_CROSSBOWif (item.flags & ITEM_CROSSBOW)
    Давайте в качестве примера разделим 1р топоры и 1р булавы через доп проверку на тип урона

    flags пример проверкипримечание
    1р булаваITEM_AXEif (item.damageType == DAM_BLUNT)
    && (item.flags & ITEM_AXE)
    1р топорITEM_AXEif (item.damageType == DAM_EDGE)
    && (item.flags & ITEM_AXE)
    2р посохITEM_2HD_AXEif (item.damageType == DAM_BLUNT)
    && (item.flags & ITEM_2HD_AXE)

  • проверка по названию instance
    Заголовок 1Заголовок 2
    Daedalus:
    var int weaponInstance; weaponInstance = Hlp_GetInstanceID(item);
    //  посохи магов воды
    if (weaponInstance == ItMW_Addon_Stab03)
    || (weaponInstance == ItMW_Addon_Stab05)
    Daedalus:
    //
    //  посохи магов огня
    if (Hlp_IsItem(item, ITMW_ADDON_STAB01) == TRUE)
    || (Hlp_IsItem(item, ITMW_ADDON_STAB04) == TRUE)

  • проверка по range
    наверное можно и тут что-то придумать , разделив условно оружие на короткое , среднее и длинное :)
 
Последнее редактирование:

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.922
Благодарности
926
Баллы
275
**
дальше попробую написать что можно сделать после того как выполнена проверка:
*заново провести расчет урона
*сделать проверку на то кто жертва и увеличить или уменьшить урон
*сделать рандом и нанести дополнительный (критический) урон
*перевести в какое то состояние после нанесения урона

***

Gratt можешь нам кратко про проверку на флаги рассказать, даёт она там какую то доп нагрузку?
 
Последнее редактирование:

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.281
Благодарности
4.581
Баллы
625
Каких-то немыслимых истин у меня нет. В скриптах арифметикологические (не считая сложных типа умножения) операции над целыми числами работают равнозначно быстро. Вопрос только в их количестве и количестве любых других проверок, так как daedalus прослойка слишком высокого уровня и вместо выполнения команд напрямую на процессоре происходит ещё куча неявного мусора. Чем меньше выполняется проверок на пути к целевому коду, тем эффективнее он будет. То же относится к выражениям. Чем меньше в выражении операторов, и чем операторы проще, тем быстрее оно выполнится.
 

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.922
Благодарности
926
Баллы
275
орки наносят критические удары

Будем разбавлять теоретическую часть практическими занятиями. Напишем простенький код который будет добавлять «криты» оркам.
Для начало наверное нам следует определить, кто атакует орки или нет:) самый простой способ (но далеко не единственный) это сделать через проверку по гильдии if (self.guild == GIL_ORC), стоит обратить внимание на то что орк в данном случае атакует , а значит он не жертва, а агрессор то есть self.
Далее мы определяем некий шанс на то будет крит или нет if (DamageRandy < 33) и если крит «проходит» увеличиваем ущерб. В данном примере я увеличу ущерб на величину урона оружия, что соответствует механики Готики damageTotal += item.damageTotal. Таким образом логически ход мысли можно записать в примерное такой вот код.
Daedalus:
func int OnDamage_Hit(var int damageTotal)
{
    if (self.guild == GIL_ORC)
    {
        Hlp_PrintConsole ("OnDamage_Hit: self.guild = GIL_ORC ");
        var int DamageRandy;    DamageRandy = Hlp_Random(100);
        if (DamageRandy < 33)
        {
            var string msg;
            msg = Str_Format("OnDamage_Hit: Critical hit [%i --> %i]",damageTotal, damageTotal+ item.damageTotal);
            Hlp_PrintConsole (msg);
            damageTotal += item.damageTotal;
            return damageTotal;
        };
    };
    return damageTotal;
};
Запустив игру я увидел в Минентале такой вот результат
OnDamage_Hit: self.guild = GIL_ORC
OnDamage_Hit: Critical hit [97 --> 167]
OnDamage_Hit: self.guild = GIL_ORC
OnDamage_Hit: self.guild = GIL_ORC
OnDamage_Hit: self.guild = GIL_ORC
OnDamage_Hit: self.guild = GIL_ORC
OnDamage_Hit: Critical hit [87 --> 147]

Как видите код получился довольно простой и я старался его именно таким и сделать, что бы отразить возможность модернизировать урон на основе старого. Главный минус данного решения в том что криты начнут «пробивать» сильно защищённого НПС, что не соответствует механики Готики :-(

Попробуем дописать код проведя расчет нового урона с "чистого листа". Всю формулу можно сделать в одну стразу и сразу отдать, но большинству понятнее когда всё идёт поэтапно: умножим урон оружия на два, затем добавим силу и отнимем броню. При этом конечно же надо помнить что PROT_EDGE и PROT_BLUNT могут отличаться. В оригинальной игре такую ситуацию связанную с орками сложно представить, но в моде вполне даже может быть :)

Daedalus:
    NewDamage = item.damageTotal * 2;
    NewDamage += self.attribute[ATR_STRENGTH];
    if (item.damagetype == DAM_EDGE)
     {
        NewDamage -= victim.protection[PROT_EDGE];
    }
    else if (item.damagetype == DAM_BLUNT)
    {
        NewDamage -= victim.protection[PROT_BLUNT];
    };

Добавив данный расчёт урона получим новую версию кода.
Daedalus:
func int OnDamage_Hit(var int OldDamageTotal)
{
    if (self.guild == GIL_ORC)
    {
        Hlp_PrintConsole ("OnDamage_Hit: self.guild = GIL_ORC ");
        var int DamageRandy;    DamageRandy = Hlp_Random(100);
        if (DamageRandy < 33)
        {
            var int NewDamage;
            NewDamage = item.damageTotal * 2;
            NewDamage += self.attribute[ATR_STRENGTH];
            if (item.damagetype == DAM_EDGE)
            {
                NewDamage -= victim.protection[PROT_EDGE];
            }
            else if (item.damagetype == DAM_BLUNT)
            {
                NewDamage -= victim.protection[PROT_BLUNT];
            };
            var string msg;
            msg = Str_Format("OnDamage_Hit: Critical hit [%i --> %i]", OldDamageTotal, NewDamage);
            Hlp_PrintConsole(msg);
            return NewDamage;
        };
    };
    return OldDamageTotal;
};
в игре я увидел тот же результат
OnDamage_Hit: self.guild = GIL_ORC
OnDamage_Hit: self.guild = GIL_ORC
OnDamage_Hit: self.guild = GIL_ORC
OnDamage_Hit: Critical hit [97 --> 167]
OnDamage_Hit: self.guild = GIL_ORC
OnDamage_Hit: Critical hit [97 --> 167]
 
Последнее редактирование:

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.922
Благодарности
926
Баллы
275
А разве в оригинале орки не могут наносить полный урон?
полный урон могут, а криты не могут ;-)

из данных ниже
OnDamage_Hit: Краш Агаш hit [100]полный урон
OnDamage_Hit: Краш Агаш Critical hit [100 --> 170]крит
OnDamage_Hit: Краш Агаш hit [9]неполный урон
 
Последнее редактирование:

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.922
Благодарности
926
Баллы
275
Топоры Орков (и не только) могут нанести крит

Прежде чем сделать шаг вперед отскочим в бок и еще раз поговорим про криты от ударов орков. Как писалось ранее отфильтровать Орков проще всего по гильдии, но можно сделать и через фильтр по оружию. В таком случае крит будут наносить не только Орки, но и брутальные люди, настоящие мужчины:) Конечно же самый просто вариант пометить оружие орков прописав какую то метку в ID инстанции. Но для данного примера, лучше пойти дальним путём и попытаться классифицировать оружие орков по неким признакам «брутальности»: во первых оружие орков двуручное, а во вторых оно требует много силы, точнее требует силы сильно больше чем наносит урона. То есть оно как бы «грубое». И вот как раз про такой тип я писал ранее в вводной теоретической части. Таким образом у нас получается следующие два условия
Daedalus:
if  (item.cond_value[2] > item.damageTotal)
&&  (item.flags & ITEM_2HD_AXE)
И вот у нас уже получился целый подкласс двуручных топоров и если в игре будут ещё какие то «брутальные» топоры они тоже дадут крит.
Заменим новыми условиями старое и получим примерной такой код
Daedalus:
func int OnDamage_Hit(var int OldDamageTotal)
{
    //if (self.guild == GIL_ORC)
    if (item.cond_value[2] > item.damageTotal)
    && (item.flags & ITEM_2HD_AXE)
    {
        var string msg;

        var int DamageRandy;    DamageRandy = Hlp_Random(100);
        if (DamageRandy < 13)
        {
            var int NewDamage;
            NewDamage = item.damageTotal * 2;
            NewDamage += self.attribute[ATR_STRENGTH];
            if (item.damagetype == DAM_EDGE)
            {
                NewDamage -= victim.protection[PROT_EDGE];
            }
            else if (item.damagetype == DAM_BLUNT)
            {
                NewDamage -= victim.protection[PROT_BLUNT];
            };
            msg = Str_Format("OnDamage_Hit: %s Critical hit [%i --> %i]", item.name, OldDamageTotal, NewDamage);
            Hlp_PrintConsole(msg);
            return NewDamage;
        };
        msg = Str_Format("OnDamage_Hit: %s hit [%i]", item.name, OldDamageTotal);
        Hlp_PrintConsole(msg);
    };
    return OldDamageTotal;
};
запустим игру и проверим как оно будет работать
OnDamage_Hit: Краш Агаш hit [9]
OnDamage_Hit: Краш Агаш hit [100]
OnDamage_Hit: Краш Агаш hit [9]
OnDamage_Hit: Краш Уррок Critical hit [90 --> 150]
OnDamage_Hit: Краш Агаш hit [100]
OnDamage_Hit: Краш Уррок hit [90]
OnDamage_Hit: Краш Агаш hit [100]
OnDamage_Hit: Краш Агаш hit [100]
OnDamage_Hit: Краш Агаш Critical hit [100 --> 170]
OnDamage_Hit: Краш Агаш hit [9]
OnDamage_Hit: Краш Уррок hit [8]
OnDamage_Hit: Краш Уррок hit [8]
OnDamage_Hit: Краш Уррок hit [90]
OnDamage_Hit: Краш Уррок Critical hit [90 --> 150]
 

Вложения

  • oDamageHelper_ITEM_ORC.zip
    162,6 KB · Просмотры: 14
Последнее редактирование:

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.922
Благодарности
926
Баллы
275
«Враг моего врага — мой друг» часть 1


Итак у нас уже жертва victim, которая вот вот получает урон. У нас есть задача провести сегрегацию.
В игре достаточно много проверок написанных пираньями. Сегрегацию авторы проводили по всем каноном: жёстко и принудительно.

Давайте с таких проверок и начнём.

C_NpcIsUndead if (C_NpcIsUndead(victim) == true)
жертва нежитьНежить может получать доп ущерб от чего то или получить сильно меньше ущерба от чего то. Или «уклоняться» с какой вероятности от удара/выстрела/магии.
C_NpcIsEvil if (C_NpcIsEvil(victim) == true)жертва Зло( враги Паладина)Такая проверка стоит на магии паладина и вы вполне её можете использовать на то что бы наносить доп урон / эффекты при использование клинков паладина или каких то других клинков прошедших освещение или что то там, что придумает автор.
C_NpcIsHero if (C_NpcIsHero(victim) == true)жертва герой
C_NpcIsDown if (C_NpcIsDown(victim))жертва лежит на земле. Без сознания, убита или магический сон.
C_DropUnconscious if (C_DropUnconscious(victim))жертва потеряет сознание, не будет убита
C_PlayerIsFakePirate if (C_PlayerIsFakePirate(victim))жертва фейк пират
C_PlayerIsFakeBandit if (C_PlayerIsFakeBandit(victim))жертва фейк бандит
***
C_NpcIsHuman if (C_NpcIsHuman(victim))жертва человек
Daedalus:
func int C_NpcIsHuman(var C_NPC slf)
{
    PrintDebugNpc        (PD_ZS_DETAIL,"C_NpcIsHuman");
    PrintDebugString    (PD_ZS_DETAIL,"...name: ", slf.name);
       
    if (slf.guild < GIL_SEPERATOR_HUM)
    {
        PrintDebugNpc    (PD_ZS_DETAIL,"...true");
        return TRUE;
    }
    else
    {
        PrintDebugNpc    (PD_ZS_DETAIL,"...false");
        return FALSE;
    };
};
C_NpcIsMonster if (C_NpcIsMonster(victim))жертва монстер
Daedalus:
func int C_NpcIsMonster(var C_NPC slf)
{
    PrintDebugNpc        (PD_ZS_DETAIL,"C_NpcIsMonster");
    PrintDebugString    (PD_ZS_DETAIL,"...name: ", slf.name);

    if ((slf.guild > GIL_SEPERATOR_HUM) && (slf.guild < GIL_SEPERATOR_ORC))
    {
        PrintDebugNpc    (PD_ZS_DETAIL,"...true");
        return TRUE;
    }
    else
    {
        PrintDebugNpc    (PD_ZS_DETAIL,"...false");
        return FALSE;
    };
};
NpcIsMonsterMage if (NpcIsMonsterMage(victim))жертва монстер маг
Огненные существа
Daedalus:
if (victim.guild == GIL_FIREGOLEM)
|| (victim.aivar[AIV_MM_REAL_ID] == ID_FIREWARAN)
|| (victim.aivar[AIV_MM_REAL_ID] == ID_DRAGON_FIRE)
|| (victim.guild == GIL_GARGOYLE)
жертва Огненное существонапример, можно нанести доп урон например от посоха магов воды
Ледяные существа
Daedalus:
if (victim.guild == GIL_ICEGOLEM)
|| (victim.aivar[AIV_MM_REAL_ID] == ID_DRAGON_ICE)
|| (victim.aivar[AIV_MM_REAL_ID] == ID_ICEWOLF)
жертва Ледяное существонапример, можно нанести доп урон например от посоха магов огня
существа которых нельзя заморозить
Daedalus:
if (victim.guild == GIL_STONEGOLEM)
|| (victim.guild == GIL_ICEGOLEM)
|| (victim.guild == GIL_FIREGOLEM)
|| (victim.guild == GIL_SUMMONED_GOLEM)
|| (victim.guild == GIL_DEMON)
|| (victim.guild == GIL_SUMMONED_DEMON)
|| (victim.guild == GIL_TROLL)
|| (victim.guild == GIL_DRAGON)
|| (victim.aivar[AIV_MM_REAL_ID] ==  ID_FIREWARAN)
|| (victim.guild == GIL_GARGOYLE)
существа которых нельзя заморозитьПираньи указывает что такие существа нельзя заморозить.
********************
C_WantToEat
C_PredatorFoundPrey
 

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.922
Благодарности
926
Баллы
275
посохи магов огня/воды с доп уроном по ледяным/огненным монстрам

будем продолжать подкреплять теорию практикой. рассмотрим простой пример того как добавить доп урон посохам магов/огня против ледяных/огненных монстров.

начнём с того что определим каким оружием был нанесён урон, в данном примере это ITMW_ADDON_STAB01 и ITMW_ADDON_STAB04
Daedalus:
//  посохи магов огня
    if (Hlp_IsItem(item, ITMW_ADDON_STAB01) == TRUE)
    || (Hlp_IsItem(item, ITMW_ADDON_STAB04) == TRUE)
    {
теперь проведём проверку на то является ли монстр "ледяным"
Daedalus:
        if (victim.guild == GIL_ICEGOLEM)
        || (victim.aivar[AIV_MM_REAL_ID] == ID_DRAGON_ICE)
        || (victim.aivar[AIV_MM_REAL_ID] == ID_ICEWOLF)
        {
похоже клиент наш и пора нанести ему доп урон. я не буду ничего не придумывать, а возьму просто криты из примера с оружием орков.
Daedalus:
            NewDamage = item.damageTotal * 2;
            NewDamage += self.attribute[ATR_STRENGTH];
            if (item.damagetype == DAM_EDGE)
            {
                NewDamage -= victim.protection[PROT_EDGE];
            }
            else if (item.damagetype == DAM_BLUNT)
            {
                NewDamage -= victim.protection[PROT_BLUNT];
            };
Но стоило мне скопировать код как я тут же заметил, что забыл добавить проверку на минимальный урон :-( если урон будет отрицательный , то жертва будет получать не "-", а "+", то есть лечиться. поэтому перед тем как отдать новый урон надо сделать еще одну проверку и сравнить его с нулём. ай нет, с минимальным :)
Daedalus:
            if (NewDamage < NPC_MINIMAL_DAMAGE)
            {
                NewDamage = NPC_MINIMAL_DAMAGE;
            };
немного самоконтроля и отдаём новый урон ледяным монстрам и возвращаем старый всем остальным.
Daedalus:
            msg = Str_Format("OnDamage_Hit: %s Critical hit [%i --> %i]", item.name, OldDamageTotal, NewDamage);
            Hlp_PrintConsole(msg);
            return NewDamage;
        };
        return OldDamageTotal;
    };

остаётся сделать тоже самое для посохов магов воды.
Daedalus:
    var int weaponInstance;    weaponInstance = Hlp_GetInstanceID(item);
    //  посохи магов воды
    if (weaponInstance == ItMW_Addon_Stab03)
    || (weaponInstance == ItMW_Addon_Stab05)
    {
        // огненные существа
        if (victim.guild == GIL_FIREGOLEM)
        || (victim.aivar[AIV_MM_REAL_ID] == ID_FIREWARAN)
        || (victim.aivar[AIV_MM_REAL_ID] == ID_DRAGON_FIRE)
        || (victim.guild == GIL_GARGOYLE)
        {
            NewDamage = item.damageTotal * 2;
            NewDamage += self.attribute[ATR_STRENGTH];
            if (item.damagetype == DAM_EDGE)
            {
                NewDamage -= victim.protection[PROT_EDGE];
            }
            else if (item.damagetype == DAM_BLUNT)
            {
                NewDamage -= victim.protection[PROT_BLUNT];
            };
            if (NewDamage < NPC_MINIMAL_DAMAGE)
            {
                NewDamage = NPC_MINIMAL_DAMAGE;
            };
            msg = Str_Format("OnDamage_Hit: %s Critical hit [%i --> %i]", item.name, OldDamageTotal, NewDamage);
            Hlp_PrintConsole(msg);
            return NewDamage;
        };
        return OldDamageTotal;
    };

запускаем игру и проверяем. всё работает. файл с кодом в архиве.

---

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

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

Вложения

  • oDamageHelper_ITEM_STAB.zip
    163,5 KB · Просмотры: 6
Последнее редактирование:

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.922
Благодарности
926
Баллы
275
функция расчёта урона от критического удара
Здесь, в Пустыне, у нас нет бумаги для контрактов, женщина. ...
Мужчина обещал — и это уже контракт.
И, как вождь, я связываю своим словом и моих людей.
в четвёртых любой кто занимается писанием профессионально или стремится к этому обратит внимание на то что расчёт урона не вынесен в отдельную функцию, а значит.. в практическом плане это значит что ошибки и огрехи будут множится и их нужно будет исправлять одно и тоже по много раз :) будем исправлять эти моменты в будущем.​
итак критический ущерб уже использовался трижды и пора его вынести в отдельную func int, которая будет производить расчёт урона от критического удара и возвращать нам уже итоговый ущерб. технически это сделать просто в связи с чем этим делом часто злоупотребляют вынося всё подряд в отдельные функции:) поэтому прежде чем такое делать надо чётко ответить себе на вопрос "зачем" и что даст это в практическом смысле. Чистый / красивый / "правильный" код это так себе аргумент, так как лучше иметь портянку которые вы сами можете читать и править, чем иметь чистый / красивый / "правильный" код который вы не способны поправить без посторонней помощи.
я считаю урон от критического удара трижды в разных местах и хочу минимизировать кол-во ошибок при его расчёте.

Итак для того что бы посчитать ущерб мне нужны self, item и victim. Старый ущерб мне не нужен, но пусть он у меня тоже будет, так как он пригодится мне как минимум для отладки и самоконтроля.
Код:
NewDamage = item.damageTotal * 2;
NewDamage += self.attribute[ATR_STRENGTH];
if (item.damagetype == DAM_EDGE)
{
           NewDamage -= victim.protection[PROT_EDGE];
}
else if (item.damagetype == DAM_BLUNT)
{
           NewDamage -= victim.protection[PROT_BLUNT];
};
 
if (NewDamage < NPC_MINIMAL_DAMAGE)
{
           NewDamage = NPC_MINIMAL_DAMAGE;
};
естественно как творец я обязан что нибудь улучшить. добавлю на свякий случай проверку на "колющий" ущерб. так же я вижу в формуле цифру два. лезу в код Готики 1 и нахожу константу DAM_CRITICAL_MULTIPLIER проверяю есть ли она в коде НВ и .. она там есть! :)
Daedalus:
CONST INT DAM_CRITICAL_MULTIPLIER                        = 2            ; //Obsolet, da Treffer-%-CHance CriticalHit ersetzt hat
значит её то я и использую в формуле, вместо цифры "2".

.. в начале файла я сразу напишу для себя пару комментариев, что бы через неделю было понятно, что это не мой новодел, а берётся из первоисточника ;-)
Daedalus:
// DAM_CRITICAL_MULTIPLIER - задаётся в  _intern\Constants.d
// NPC_MINIMAL_DAMAGE - задается в  AI\AI_Intern\AI_Constants.d

// ФОРМУЛА КРИТА (itm.damageTotal * DAM_CRITICAL_MULTIPLIER) +  slf.attribute[ATR_STRENGTH] - vctim.protection[PROT_****]
ну и в новой func int тоже подпишу что есть что
Daedalus:
func int onDamage_CriticalHit(var C_Npc slf,            // агрессор
                              var C_Npc vctim,          // жертва
                              var C_Item itm,           // оружие агрессора
                              var int OldDamageTotal)   // старый ущерб
и наконец сам расчёт урона..
Daedalus:
{
    var string msg;
    var int NewDamage;

    NewDamage = (itm.damageTotal * DAM_CRITICAL_MULTIPLIER);
    NewDamage += slf.attribute[ATR_STRENGTH];
    if (itm.damagetype == DAM_EDGE)
    {
        NewDamage -= vctim.protection[PROT_EDGE];
    }
    else if (itm.damagetype == DAM_BLUNT)
    {
        NewDamage -= vctim.protection[PROT_BLUNT];
    }
    else if (itm.damagetype == DAM_POINT)
    {
        NewDamage -= vctim.protection[PROT_POINT];
    };
    if (NewDamage < NPC_MINIMAL_DAMAGE)
    {
        NewDamage = NPC_MINIMAL_DAMAGE;
    };
    msg = Str_Format("OnDamage_Hit[%s]: Critical hit %s", vctim.name, itm.name);
    msg = Str_Format("%s [%i --> %i]", msg, OldDamageTotal, NewDamage);
    Hlp_PrintConsole(msg);
    return NewDamage;
};
сохраняю своё творение в файл onDamage_CriticalHit.d

осталось поправить файл с функцией OnDamage_Hit для посохов магов огня / воды. кода теперь в нём будет сильно меньше:)
Daedalus:
META
{
      after = onDamage_CriticalHit.d;
};


func int OnDamage_Hit(var int OldDmgTotal)
{
    var string msg;
    var int NewDamage;
    //  посохи магов огня
    if (Hlp_IsItem(item, ITMW_ADDON_STAB01) == TRUE)
    || (Hlp_IsItem(item, ITMW_ADDON_STAB04) == TRUE)
    {
        if (victim.guild == GIL_ICEGOLEM)
        || (victim.aivar[AIV_MM_REAL_ID] == ID_DRAGON_ICE)
        || (victim.aivar[AIV_MM_REAL_ID] == ID_ICEWOLF)
        {
            return onDamage_CriticalHit(self, victim, item, OldDmgTotal);
        };
        return OldDmgTotal;
    };

    var int weaponInstance;    weaponInstance = Hlp_GetInstanceID(item);
    //  посохи магов воды
    if (weaponInstance == ItMW_Addon_Stab03)
    || (weaponInstance == ItMW_Addon_Stab05)
    {
        // огненные существа
        if (victim.guild == GIL_FIREGOLEM)
        || (victim.aivar[AIV_MM_REAL_ID] == ID_FIREWARAN)
        || (victim.aivar[AIV_MM_REAL_ID] == ID_DRAGON_FIRE)
        || (victim.guild == GIL_GARGOYLE)
        {
            return onDamage_CriticalHit(self, victim, item, OldDmgTotal);
        };
        return OldDmgTotal;
    };
 
    return OldDmgTotal;
};
обратите внимание что ввиду того что это инъекция я использовал META в zParserExtender что бы определить что данный файл идёт после onDamage_CriticalHit.
не пренебрегайте(!) подобными вещами периодически чётко указывая машине кто тут главный ;-)
Код:
META
{
      after = onDamage_CriticalHit.d;
};
игра запускается. криты идут.
 

Вложения

  • OnDamage_Hit_ITEM_STAB_v_1.2.zip
    164,1 KB · Просмотры: 16
Последнее редактирование:

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.922
Благодарности
926
Баллы
275
del
 
Последнее редактирование:

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.281
Благодарности
4.581
Баллы
625
Ты используешь тот который был выложен позже. Смотри даты сообщений.
 

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
1.922
Благодарности
926
Баллы
275
функция расчёта урона с учётом бонусов от силы и/или ловкости
предположим мы хотим разным типам оружия давать разные бонусы от силы / ловкости персонажа. в таком случае нам понадобится какая то func int которая будет рассчитывать урон и возвращать его. читайте так же функция расчёта урона от критического удара.

для расчёта урона понадобится отдать self, item и victim, а так же коэффициенты для бонуса(процент) от силы и ловкости
Daedalus:
func int onDamage_ScalinglHit(var C_Npc slf,    // агрессор
                              var C_Npc victm,  // жертва
                              var C_Item itm,   // оружие агрессора
                              var int str,      // процент для силы
                              var int dex)      // процент для ловкости
для начало посчитаем бонусы от силы и ловкости и добавим их к урону оружия
Daedalus:
    var int NewDmgTotal;
    var int ScalingStr;
    var int ScalingDex;
    var string msg;
 
    ScalingStr = (slf.attribute[ATR_STRENGTH] * str / 100);
    ScalingDex = (slf.attribute[ATR_DEXTERITY] * dex / 100);
    NewDmgTotal = (itm.DamageTotal + ScalingStr + ScalingDex);

    msg = Str_Format("onDamage_ScalinglHit: %s[%i]", itm.name, itm.DamageTotal);
    msg = Str_Format("%s + ScalingStr[%i] + ScalingDex[%i]", msg, ScalingStr, ScalingDex);
    Hlp_PrintConsole(msg);
теперь можно определить навык владения оружием которым НПС наносит удар
Daedalus:
    var int SlfHitChance;
    if      (itm.flags & ITEM_DAG)         { SlfHitChance = slf.HitChance[NPC_TALENT_1H];       }
    else if (itm.flags & ITEM_SWD)         { SlfHitChance = slf.HitChance[NPC_TALENT_1H];       }
    else if (itm.flags & ITEM_AXE)         { SlfHitChance = slf.HitChance[NPC_TALENT_1H];       }
    else if (itm.flags & ITEM_2HD_SWD)     { SlfHitChance = slf.HitChance[NPC_TALENT_2H];       }
    else if (itm.flags & ITEM_2HD_AXE)     { SlfHitChance = slf.HitChance[NPC_TALENT_2H];       }
    else if (itm.flags & ITEM_BOW)         { SlfHitChance = slf.HitChance[NPC_TALENT_BOW];      }
    else if (itm.flags & ITEM_CROSSBOW)    { SlfHitChance = slf.HitChance[NPC_TALENT_CROSSBOW]; };
посчитаем шанс нанесения полного урона. Здесь используется CoefficientDamage что бы в моде можно было изменить формулу расчёта полного / неполного урона.
Daedalus:
    var int DamageRandy;
    var int CoefficientDamage;
    DamageRandy = Hlp_Random (100) + 1;    // [0-99] --> [1-100]
    if (DamageRandy <= SlfHitChance)
    {
        CoefficientDamage = 100;
    }
    else
    {
        CoefficientDamage = 10;  // const int NPC_MINIMAL_PERCENT    = 10;
    };
    msg = "onDamage_ScalinglHit --> CoefficientDamage = ";
    msg = Str_Format("%s %i  [%i / %i]", msg, CoefficientDamage, DamageRandy, SlfHitChance);
    Hlp_PrintConsole (msg);
 
    NewDmgTotal =  NewDmgTotal * CoefficientDamage / 100;
    msg = Str_Format("onDamage_ScalinglHit[%s]: ScalingDmg[%i]", victm.name, NewDmgTotal);
остаётся учесть защиту жертвы и отдать итоговый урон
Daedalus:
    var int VictmProtection;
    if      (itm.damagetype == DAM_EDGE)    { VictmProtection = victm.protection[PROT_EDGE];  }
    else if (itm.damagetype == DAM_BLUNT)   { VictmProtection = victm.protection[PROT_BLUNT]; }
    else if (itm.damagetype == DAM_POINT)   { VictmProtection = victm.protection[PROT_POINT]; };
 
    NewDmgTotal -= VictmProtection;
    if (NewDmgTotal < NPC_MINIMAL_DAMAGE)
    {
        NewDmgTotal = NPC_MINIMAL_DAMAGE;
    };
    msg = Str_Format("%s - Prt[%i] = DmgTotal[%i]", msg, VictmProtection, NewDmgTotal);
    Hlp_PrintConsole(msg);
    return NewDmgTotal;
};
сохраним написанную функцию в отдельный файл и попробуем её использовать :)

***
***


Daedalus:
func int OnDamage_Hit(var int damageTotal)
{
    //  ОДНОРУЧНОЕ
    if (item.flags & ITEM_SWD)      { return  onDamage_ScalinglHit(self, victim, item, 50, 40); };
    if (item.flags & ITEM_Axe)      { return  onDamage_ScalinglHit(self, victim, item, 70, 30); };
 
    //  ДВУРУЧНОЕ
    if (item.flags & ITEM_2HD_SWD)  { return  onDamage_ScalinglHit(self, victim, item, 80, 40); };
    if (item.flags & ITEM_2HD_Axe)  { return  onDamage_ScalinglHit(self, victim, item, 100, 30); };
 
    // луки
    if (item.flags & ITEM_BOW)      { return  onDamage_ScalinglHit(self, victim, item, 0, 100); };
    // арбалеты
    if (item.flags & ITEM_CROSSBOW) { return  onDamage_ScalinglHit(self, victim, item, 40, 80); };
 
    return damageTotal;
};
onDamage_ScalinglHit: Широкий меч[40] + ScalingStr[25] + ScalingDex[20]
onDamage_ScalinglHit --> CoefficientDamage = 10 [36 / 30]
onDamage_ScalinglHit: ScalingDmg[8] - Prt[70] = DmgTotal[5]

onDamage_ScalinglHit: Длинный рудный меч[60] + ScalingStr[40] + ScalingDex[33]
onDamage_ScalinglHit --> CoefficientDamage = 100 [31 / 90]
onDamage_ScalinglHit: ScalingDmg[133] - Prt[100] = DmgTotal[33]

onDamage_ScalinglHit: Широкий меч[40] + ScalingStr[25] + ScalingDex[20]
onDamage_ScalinglHit --> CoefficientDamage = 100 [29 / 30]
onDamage_ScalinglHit: ScalingDmg[85] - Prt[70] = DmgTotal[15]

onDamage_ScalinglHit: Меч паладина[60] + ScalingStr[75] + ScalingDex[60]
onDamage_ScalinglHit --> CoefficientDamage = 10 [77 / 75]
onDamage_ScalinglHit: ScalingDmg[19] - Prt[70] = DmgTotal[5]

onDamage_ScalinglHit: Меч паладина[60] + ScalingStr[75] + ScalingDex[60]
onDamage_ScalinglHit --> CoefficientDamage = 100 [5 / 75]
onDamage_ScalinglHit: ScalingDmg[195] - Prt[70] = DmgTotal[125]
 

Вложения

  • ScalinglHit.zip
    163,6 KB · Просмотры: 24
Последнее редактирование:
Сверху Снизу