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

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

Готика ½ Spell_Logic - отнимаем(инвестируем) ману движком :: SPL_RECEIVEINVEST :: SPL_FORCEINVEST

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.001
Благодарности
969
Баллы
295
пришёл такой вот вопрос
хачу что бы мана отнялась как у тебя! как сделать для демана и голема.
Spell_Logic_InvestedCAST Vs Spell_Logic_FastCAST

Прототипы Spell_Logic Spell_Logic_FastCAST Spell_Logic_InvestedCAST


    • Spell_Logic_InvestedCAST - будет отнимать(инвестировать) ману постепенно, как в Готики 1
    • Spell_Logic_FastCAST - будет отнимать ману "мгновенно", как в Готики 2

    ВАЖНО! если заклинание имеет "долгую" анимацию(например заклинание призыва, буря, страх), то можно использовать Spell_Logic_InvestedCAST. В этом случае мана будет отниматься(инвестироваться) постепенно(плавно), но следует понимать что применение Spell_Logic_InvestedCAST требует дополнительных тестов и проверок в игре, так как инвестирование большого кол-ва маны может занять бОльшее кол-во времени чем длится анимация заклинания, что может привести к увеличению времени каста. Яркий тому пример это огненный дождь, анимация которого занимает меньшее время чем инвестирование 150 маны.
  • Daedalus:
    func int Spell_Logic_FastCAST(var c_npc slf, var int manaInvested,var int Spl_Cost_Mana)
    {
        // Ночь Ворона. Начало
        if (Npc_GetActiveSpellIsScroll(slf)) // это свиток
        {
            Spl_Cost_Mana = SPL_Cost_Scroll; // меняет значение для Spl_Cost_Mana для NotR
        };
        // Ночь Ворона. Конец
    
        if (manainvested == 0)
        {
            if (slf.attribute[ATR_MANA] < Spl_Cost_Mana)
            {
                return SPL_SENDSTOP; // маны мало --> выход
            };
            return SPL_FORCEINVEST + Spl_Cost_Mana; // отнимает ману. устанавливаем новое значение manainvested.
        };
     
        return SPL_SENDCAST; // кидаем
    };
    подробнее про Spell_Logic_FastCAST можно почитать тут Готика ½ - Spell_Logic - увеличения урона заклинаний

  • Daedalus:
    func int Spell_Logic_InvestedCAST(var c_npc slf, var int manaInvested,var int Spl_Cost_Mana)
        {
            // Ночь Ворона. Начало
            if (Npc_GetActiveSpellIsScroll(slf)) // это свиток
            {
                Spl_Cost_Mana = SPL_Cost_Scroll; // меняет значение для Spl_Cost_Mana для NotR
            };
            // Ночь Ворона. Конец
    
    
            if (manainvested == 0)
            {
                if (slf.attribute[ATR_MANA] < Spl_Cost_Mana)
                {
                    return SPL_SENDSTOP; // маны мало --> выход
                };
            };
     
            if (manainvested > Spl_Cost_Mana)
            {
                return SPL_SENDCAST; // кастуем
            };
     
            return SPL_RECEIVEINVEST ; // отнимает ману
        };




давайте посмотрим как изменится код на примере заклинания призыва голема

ману отнимают скрипты (G2 NotR MDK)ману отнимает движок(улучшения)
Daedalus:
func int Spell_Logic_SummonGolem (var int manaInvested)
{
    if (Npc_GetActiveSpellIsScroll(self) && (self.attribute[ATR_MANA] >= SPL_Cost_Scroll))
    {
        return SPL_SENDCAST;
    }
    else if (self.attribute[ATR_MANA] >= SPL_Cost_SummonGolem)
    {
        return SPL_SENDCAST;
    }
    else //nicht genug Mana
    {
        return SPL_SENDSTOP;
    };
};
Daedalus:
func int Spell_Logic_SummonGolem (var int manaInvested)
{
    //return Spell_Logic_FastCAST(self, manaInvested, SPL_Cost_SummonGolem);
    return Spell_Logic_InvestedCAST(self, manaInvested, SPL_Cost_SummonGolem);
};
Daedalus:
func void Spell_Cast_SummonGolem()
{
    if (Npc_GetActiveSpellIsScroll(self))
    {
        self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Scroll;
    }
    else
    {
        self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_SummonGolem;
    };
    if (Npc_IsPlayer(self))
    {
        Wld_SpawnNpcRange( self,Summoned_Golem,1,500);
    }
    else
    {
        Wld_SpawnNpcRange( self,StoneGolem,1,500);
    };
    self.aivar[AIV_SelectSpell] += 1;
};
Daedalus:
func void Spell_Cast_SummonGolem()
{
    if (Npc_IsPlayer(self))
    {
        Wld_SpawnNpcRange( self,Summoned_Golem,1,500);
    }
    else
    {
        Wld_SpawnNpcRange( self,StoneGolem,1,500);
    };
    self.aivar[AIV_SelectSpell] += 1;
};
 
Последнее редактирование:

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.001
Благодарности
969
Баллы
295
На движке НВ ману будут отнимать SPL_RECEIVEINVEST и SPL_FORCEINVEST.
Надо пару строчек написать: скрипты позволяют делать почти всё, но при этом они нужны не для всего. Иногда решая какую то задачу или реализую какую то идею можно написать рабочую простыню и это будет хорошо для общего развития. Но гляди на такие «Чудеса на виражах»* понимаешь что это должен был делать движок .. небольшой патч/фикс на Юнион в пять строчек будет как правило эффективнее решить такую задачу.

***

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

в первой итерации (manainvested == 0) делаем проверку на то хватит ли у НПС маны на каст: если маны изначально не хватает то Spell_Logic будем возвращать SPL_SENDSTOP, иначе будет отниматся мана и изменяем значение manainvested , используя SPL_FORCEINVEST.
при (manainvested >= Spl_Cost_Mana) будем делать каст SPL_SENDCAST.
Daedalus:
func int Spell_Logic_FastCAST (var c_npc slf, var int manaInvested,var int Spl_Cost_Mana)
{
    // Ночь Ворона. Начало
    if (Npc_GetActiveSpellIsScroll(slf)) // это свиток
    {
        Spl_Cost_Mana = SPL_Cost_Scroll; // меняет значение для Spl_Cost_Mana для NotR
    };
    // Ночь Ворона. Конец

    if (manainvested == 0)
    {
        if (slf.attribute[ATR_MANA] < Spl_Cost_Mana)
        {
            return SPL_SENDSTOP; // маны мало --> выход
        };
        return SPL_FORCEINVEST + Spl_Cost_Mana; // отнимает ману. устанавливаем новое значение manainvested.
    };
 
    return SPL_SENDCAST; // кидаем
};
//ввиду того что это функция int, то часть явных проверок в шаблоне я опустил//


Давайте теперь его применим на паре заклинаний.


IceBolt используют враги скелеты маги, поэтому в Spell_Cast, происходит запись в AIV_SelectSpell
Daedalus:
func int Spell_Logic_IceBolt(var int manaInvested)
{
    return Spell_Logic_FastCAST(self,manaInvested,SPL_Cost_IceBolt);
};

func void Spell_Cast_IceBolt()
{
    self.aivar[AIV_SelectSpell] += 1; // использует маг скелет
};

Заклинание "уничтожение нежити" прочие НПС не используют. поэтому в Spell_Cast прописывать AIV_SelectSpell ненадо!
Daedalus:
func int Spell_Logic_DestroyUndead(var int manaInvested)
{
    return Spell_Logic_FastCAST(self,manaInvested,SPL_Cost_DESTROYUNDEAD);
};

func void Spell_Cast_DestroyUndead()
{
    // ИИ не использует
};


p.s.
писал по памяти. на работе поищу рабочую версию, может что то забыл.

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

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.001
Благодарности
969
Баллы
295
Яркий тому пример это огненный дождь, анимация которого занимает меньшее время чем инвестирование 150 маны.
пример "смешанного" использования SPL_RECEIVEINVEST и SPL_FORCEINVEST для огненного дождя
Daedalus:
// ************
// SPL_FireRain
// ************

func int Spell_Logic_Firerain(var int manaInvested)
{
    var int manaSplCost;

    if (manaInvested == 0)
    {
        if (Npc_GetActiveSpellIsScroll(self))    { manaSplCost = SPL_Cost_Scroll;   }
        else                                     { manaSplCost = SPL_Cost_FireRain; };
  
        if (self.attribute[ATR_MANA] < manaSplCost)
        {
            return SPL_SENDSTOP;
        };
        return SPL_NEXTLEVEL; //  для доп. анимации заклинания "огненный дождь"
    };
 
    if (manaInvested >= manaSplCost)
    {
        return SPL_SENDCAST;
    };
    if (manaInvested == 1)
    {
        return SPL_FORCEINVEST + (manaSplCost * 2 / 5); // единовременно отнимает 40% маны необходимых для каста
    };
    return SPL_RECEIVEINVEST; // инвестирует оставшиеся 60% маны
};


func void Spell_Cast_Firerain()
{
    self.aivar[AIV_SelectSpell] += 1;   // для ищущих
};
 
Последнее редактирование:

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.001
Благодарности
969
Баллы
295
итак.. выяснился неприятный баг. при инвестирование маны движок Готики 2 НВ , делает отсечку если у героя остаётся 1 маны и не позволяет герою использовать свою последнюю единичку маны. скорее всего эту печать можно как пофиксить с помощью Юнион. Мои познания в этом крайне скудны, поэтому временным решением может быть костыль на скриптах, который будет повышать ману, а перед кастом отнимать образовавшееся "сальдо" на скриптах.

Daedalus:
    // костыль №2 "secretmana" -> начало
    var int secretmana;
    if  (self.attribute[ATR_MANA] == 2)
    {
        self.attribute[ATR_MANA] += 1;
        secretmana+= 1;
    };
     
    if  (manaInvested > SPL_SENDCAST_Transform)
    {
        // костыль №2 "secretmana" -> продолжение
        if (secretmana > 0)
        {
            self.attribute[ATR_MANA] -= secretmana;
        };
        secretmana = 0;
       
        Npc_SetActiveSpellInfo(self, itm.hp); // в кого превращаться берётся из инстанции свитка/руны
        return SPL_SENDCAST;
    };

привожу общий спелл логик для заклинаний трансформации. в нём в том числе вызываться визуальный эффект из VISUALFX по методике D36. и используется изменение скорости инвестирования суть которой я подглядел в модфиксе ElderGamer
Daedalus:
INSTANCE Spell_Transform (C_Spell_Proto)
{
    time_per_mana            = 0;
    spelltype                 = SPELL_BAD;
    targetCollectAlgo        = TARGET_COLLECT_NONE;
    canTurnDuringInvest        = 0;
    targetCollectRange        = 0;
    targetCollectAzi        = 0;
    targetCollectElev        = 0;
};

const int SPL_Charge_Frames = 32;

func int Spell_Logic_Transform(var int manaInvested,var c_item itm)
{      
    Hlp_msg = Str_Format("  Spell_Logic_Transform[%s] :: %s invested Mana =  %i" ,self.name, itm.description, manaInvested);
    Hlp_PrintConsole(Hlp_msg);
   
    // устанавливаем значение маны необходимое для каста
    var int SPL_SENDCAST_Transform;
    SPL_SENDCAST_Transform = itm.cond_value[2];

    if (manaInvested == 0)
    {  
        if (self.attribute[ATR_MANA] < SPL_SENDCAST_Transform)
        {
            // пока используется костыль. потом или снять или сделать фековое заклинание
            return SPL_SENDSTOP;
        };
    };

    // дополнительный визуальный эффект у закл. трансформация,
    // подробнее смотри  тут https://worldofplayers.ru/threads/42298/post-1163248
    if (Npc_GetActiveSpellLevel(self) <= SPL_Charge_Frames)
    {
        if (Npc_GetActiveSpellLevel(self) == SPL_Charge_Frames)
        && (manaInvested != 1)
        {
            return SPL_FORCEINVEST + 1;
        };
        return SPL_NEXTLEVEL;
    };


     
    // меняем скорость инвестирования маны
    var int tpm;    tpm = FloatToInt(Spell_Transform.time_per_mana);
    if (tpm == 0)
    {
        // добавить проверку на стоимость каста и менять скорость инвестирования
        if      (SPL_SENDCAST_Transform <= 5)    { Spell_Transform.time_per_mana = 250;  }
        else if (SPL_SENDCAST_Transform <= 10)   { Spell_Transform.time_per_mana = 125;  }
        else if (SPL_SENDCAST_Transform <= 15)   { Spell_Transform.time_per_mana = 83;   }
        else if (SPL_SENDCAST_Transform <= 20)   { Spell_Transform.time_per_mana = 63;   }
        else                                     { Spell_Transform.time_per_mana = 50;   };
    };
   
   

    // костыль №2 "secretmana" -> начало
    var int secretmana;
    if  (self.attribute[ATR_MANA] == 2)
    {
        self.attribute[ATR_MANA] += 1;
        secretmana+= 1;
    };
     
   
   
    if  (manaInvested > SPL_SENDCAST_Transform)
    {
        // костыль №2 "secretmana" -> продолжение
        if (secretmana > 0)
        {
            self.attribute[ATR_MANA] -= secretmana;
        };
        secretmana = 0;
       
        Hlp_PrintConsole("      -> return SPL_SENDCAST");
        Npc_SetActiveSpellInfo(self, itm.hp);
        PlayerIsTransformed = 0;        //
        B_StartMagicTransform(self);    // фиксация уровня героя, его оружия и прочее
        return SPL_SENDCAST;
    };
   
    Hlp_msg = Str_Format("  Spell_Logic_Transform[%s] :: %s Real Mana =  %i -> return SPL_RECEIVEINVEST" ,self.name, itm.description, self.attribute[ATR_MANA]);
    Hlp_PrintConsole(Hlp_msg);  
    return SPL_RECEIVEINVEST;
};
 
Сверху Снизу