MaNGOS Core

Форум любителей MaNGOS


    Пример скрипта ScriptDev2

    Поделиться
    avatar
    KiriX
    Admin
    Admin

    Сообщения : 42
    Очки : 60
    Дата регистрации : 2009-04-15
    Возраст : 32
    Откуда : Петрозаводск

    Пример скрипта ScriptDev2

    Сообщение автор KiriX в Вт Май 05, 2009 11:54 pm

    Возьмём пример скрипта первого попавшегося НПС из файла ScriptDev2\scripts\zone\alterac_mountains\alterac_mountains.cpp
    Код:
    /*######
    ## npc_ravenholdt
    ######*/

    struct MANGOS_DLL_DECL npc_ravenholdtAI : public ScriptedAI
    {
        npc_ravenholdtAI(Creature *c) : ScriptedAI(c) { Reset(); }

        void Reset() { }

        void MoveInLineOfSight(Unit *who)
        {
            if( who->GetTypeId() == TYPEID_PLAYER )
                if( ((Player*)who)->GetQuestStatus(6681) == QUEST_STATUS_INCOMPLETE )
                    ((Player*)who)->KilledMonster(m_creature->GetEntry(),m_creature->GetGUID() );
        }
    };
    CreatureAI* GetAI_npc_ravenholdt(Creature *_Creature)
    {
        return new npc_ravenholdtAI (_Creature);
    }
    Первые 3 строки - комментарий с пояснением, какой именно НПС скпиртуется.
    struct MANGOS_DLL_DECL npc_ravenholdtAI : public ScriptedAI
    С этой строки, собственно, начинается тело самого скрипта, название которого, соответственно npc_ravenholdtAI.
    Следующие две строки кода - обнуление, сброс скрипта (вот честно - я хз, зачем это делается =) )
    Далее: void MoveInLineOfSight(Unit *who) - это событие, происходящее при появлении в зоне LOS НПС какого-либо юнита (к примеру, и что нам как раз и нужно, игрока).
    Далее: if( who->GetTypeId() == TYPEID_PLAYER ) если появившийся юнит игрок...
    далее: if( ((Player*)who)->GetQuestStatus(6681) == QUEST_STATUS_INCOMPLETE ) если у него есть квест 6681 и он неокончен (QUEST_STATUS_INCOMPLETE), то
    далее: ((Player*)who)->KilledMonster(m_creature->GetEntry(),m_creature->GetGUID() ); данному юниту засчитывается убийство данной цели (НПС).
    Может слишком бегло, тогда пишите что именно интересно и непонятно, попробум разобраться глубже.

    А вообще странно, что этот скрипт делает в коде - ему самое место в EventAI - там это легко реализуется.

    danbst

    Сообщения : 6
    Очки : 8
    Дата регистрации : 2009-04-16

    Re: Пример скрипта ScriptDev2

    Сообщение автор danbst в Ср Май 06, 2009 5:10 am

    >>>А вообще странно, что этот скрипт делает в коде - ему самое место в EventAI - там это легко реализуется.
    наверно, такой фичи в ЕвентАИ еще не было тогда. А вообщем, НоФантази сказал, что если скрипт легко сделать через ЕвентАИ - то делайте и не заморачивайтесь.

    Продолжу мануал по скриптам, в более общем виде (опять по примеру, который можна сделать и через ЕвентАИ).
    Код:
    struct MANGOS_DLL_DECL boss_spiritlynxAI : public ScriptedAI
    {
        boss_spiritlynxAI(Creature* pCreature) : ScriptedAI(pCreature)
        {
            pInstance = ((ScriptedInstance*)pCreature->GetInstanceData());
            Reset();
        }

        ScriptedInstance* pInstance;

        uint32 uiFrenzyTimer;
        uint32 uiShredArmorTimer;

        void Reset()
        {
            uiFrenzyTimer = (10+rand()%10)*1000;                //first frenzy after 10-20 seconds
            uiShredArmorTimer = 4000;
        }

        void EnterCombat(Unit* pWho)
        {
            DoZoneInCombat();
        }

        void KilledUnit(Unit* pVictim)
        {
            if (!pInstance)
                return;

            if (Creature* pHalazzi = ((Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_HALAZZI))))
                ((boss_halazziAI*)pHalazzi->AI())->KilledUnit(pVictim);
        }

        void UpdateAI(const uint32 uiDiff)
        {
            if (!m_creature->SelectHostilTarget() || !m_creature->getVictim())
                return;

            if (uiFrenzyTimer < uiDiff)
            {
                DoCast(m_creature, SPELL_LYNX_FRENZY);
                uiFrenzyTimer = (20+rand()%10)*1000;            //subsequent frenzys casted every 20-30 seconds
            }
            else
                uiFrenzyTimer -= uiDiff;

            if (uiShredArmorTimer < uiDiff)
            {
                DoCast(m_creature->getVictim(), SPELL_SHRED_ARMOR);
                uiShredArmorTimer = 4000;
            }
            else
                uiShredArmorTimer -= uiDiff;

            DoMeleeAttackIfReady();
        }
    };

    CreatureAI* GetAI_boss_spiritlynxAI(Creature* pCreature)
    {
        return new boss_spiritlynxAI (pCreature);
    }

     void AddSC_boss_halazzi()
     {
        Script* newscript;

        newscript = new Script;
        newscript->Name = "boss_halazzi";
        newscript->GetAI = &GetAI_boss_halazzi;
        newscript->RegisterSelf();

        newscript = new Script;
        newscript->Name = "boss_spiritlynx";
        newscript->GetAI = &GetAI_boss_spiritlynxAI;
        newscript->RegisterSelf();
     }
    boss_spiritlynxAI(Creature* pCreature) : ScriptedAI(pCreature) - конструктор класса. Тоесть, все что записано в конструкторе выполнится единожды за время существования кричера. Обязателен
    void Reset() - тут мы устанавливаем дефолтные значения (таймеры и прочая лабудень). Пример: моб создался - установили дефолт, моб заагрился и вышел из боя - установили дефолт, моб умер - установили дефолт (да да, если моб создается сразу мертвым, мы можем попасть в эту ф-ию и сделать необходимые нам проверки)
    void EnterCombat(Unit* pWho) - (бывшая Aggro(Unit *who)) ф-ия вызывается при аггро игрока (или моба), который и передается через параметр.Не вызывается при смене игроков, только один раз за бой. Если был передан игрок - то можем делать так:
    if (who->GetTypeId() == TYPEID_PLAYER)
    ((Player*)who)->DoSomeThing();
    DoZoneInCombat() - заставить всех игроков вокруг моба войти в бой с этим мобом
    void KilledUnit(Unit* pVictim) - комментарии лишние
    void UpdateAI(const uint32 uiDiff) - очень важная ф-ия. Позволяет мобу делать что-то по таймерам и событиям. Вызывается постоянно, через каждые uiDiff миллисекунд. В данном примере показаны реализации двух таймеров.

    Важная часть, о которой не упомянул админчеГ. Чтоб скрипт заработал, его нужно зарегистрировать. Если вы дописываете скрипт в уже существующий файл, то вконце как правило есть ф-ия void AddSC_blabla_bla() . В нее мы и регистрируем скрипт по примеру выше. Если же вы пишете совсем новый скрипт в совсем новом файле (типу новые инсты ВотЛКа скриптуете) - то этого недостаточно. Необходимо потом включить вашу ф-ию void AddSC_blabla_bla() в основной файл - ScriptMgr.cpp. Делаеться просто - вставляем строчку AddSC_blabla_bla(); где-нибудь между подобных, а также строчку extern void AddSC_blabla_bla(); между подобных. Все.

    Очень просто изучать скрипты, рассматривая уже готовые. Благо их очень много и много разнообразных. Как идеал, смотрите скрипт Иллидана - там реализованы почти все возможности скриптов.

    Ну и весь список дополнительных функций в сриптдеве (взято из файла sc_creature.h), если нужны русские каменты - пишите:
    Код:
        //*************
        //CreatureAI Functions
        //*************

    //Определяет, видимый ли игрок мобу. Сдесь можно вставить проверку на стелс, на расстояние и тп..
        bool IsVisible(Unit *who) const;

        //Вызывается каждый раз, когда предыдущая ф-ия возвращает значение  true
        void MoveInLineOfSight(Unit *);

        //Called at each attack of m_creature by any victim
        void AttackStart(Unit *);

        // Вызывается при аггро моба, единожды за бой
        void EnterCombat(Unit *);

        // Ивейд моба, то есть нету больше целей и выход из боя
        void EnterEvadeMode();

        //Called at any heal cast/item used (call non implemented in mangos)
        void HealBy(Unit *healer, uint32 amount_healed) {}

        // Вызывается каждый раз, когда моб наносит удар врагу. Вызывается ДО реального нанесения урона, поэтому сдесь можна подредактировать урон
        void DamageDeal(Unit *done_to, uint32 &damage) {}

        // Аналогично, если кто-то бьет по мобу
        void DamageTaken(Unit *done_by, uint32 &damage) {}

        // Вызывается при  каждом обновлении мира, главная
        void UpdateAI(const uint32);

        // Вызывается ПЕРЕД смертью моба
        void JustDied(Unit*){}

        //Called at creature killing another unit
        void KilledUnit(Unit*){}

        // Если вы использовали SummonCreature(), то сдесь можна инициализовать суммона, вызывается при каждом суммоне
        void JustSummoned(Creature* ) {}

        // Called when a summoned creature is despawned
        void SummonedCreatureDespawn(Creature* /*unit*/) {}

        // Called when hit by a spell
        void SpellHit(Unit*, const SpellEntry*) {}

        // Called when creature is spawned or respawned (for reseting variables)
        void JustRespawned();

        //Called at waypoint reached or PointMovement end
        void MovementInform(uint32, uint32){}

        //*************
        // Variables
        //*************

        //*************
        //Pure virtual functions
        //*************

        // Если существо только респаунилось, только что ивейдилось, только-что умерло - вызывается эта ф-ия, установка дефолтных значений
        virtual void Reset() = 0;

        //*************
        //AI Helper Functions
        //*************

        //Start movement toward victim
        void DoStartMovement(Unit* victim, float distance = 0, float angle = 0);

        //Start no movement on victim
        void DoStartNoMovement(Unit* victim);

        // Эта ф-ия делает мили удары. Как правило, нужно вставлять в void UpdateAI(const uint32); чтоб било постоянно, но можна и убрать. Тогда моб не будет физ демажить
        void DoMeleeAttackIfReady();

        //Stop attack of current victim
        void DoStopAttack();

        //Cast spell by Id
        void DoCast(Unit* victim, uint32 spellId, bool triggered = false);

        //Cast spell by spell info
        void DoCastSpell(Unit* who,SpellEntry const *spellInfo, bool triggered = false);

        //Plays a sound to all nearby players
        void DoPlaySoundToSet(Unit* unit, uint32 sound);

        //Places the entire map into combat with creature
        void DoZoneInCombat(Unit* pUnit = 0);

        //Drops all threat to 0%. Does not remove players from the threat list
        void DoResetThreat();

        //Teleports a player without dropping threat (only teleports to same map)
        void DoTeleportPlayer(Unit* pUnit, float x, float y, float z, float o);

        //Returns friendly unit with the most amount of hp missing from max hp
        Unit* DoSelectLowestHpFriendly(float range, uint32 MinHPDiff = 1);

        //Returns a list of friendly CC'd units within range
        std::list DoFindFriendlyCC(float range);

        //Returns a list of all friendly units missing a specific buff within range
        std::list DoFindFriendlyMissingBuff(float range, uint32 spellid);

        // Функция суммонинга
        Creature* DoSpawnCreature(uint32 id, float x, float y, float z, float angle, uint32 type, uint32 despawntime);

        // Выбрать юнита. Можно выбрать рандомного, топаггро, самый маленький аггро
        Unit* SelectUnit(SelectAggroTarget target, uint32 position);

        //Returns spells that meet the specified criteria from the creatures spell list
        SpellEntry const* SelectSpell(Unit* Target, int32 School, int32 Mechanic, SelectTarget Targets,  uint32 PowerCostMin, uint32 PowerCostMax, float RangeMin, float RangeMax, SelectEffect Effect);

        //Checks if you can cast the specified spell
        bool CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered = false);

        void SetEquipmentSlots(bool bLoadDefault, int32 uiMainHand = EQUIP_NO_CHANGE, int32 uiOffHand = EQUIP_NO_CHANGE, int32 uiRanged = EQUIP_NO_CHANGE);

        void SetSheathState(SheathState newState);

        void SetCombatMovement(bool bCombatMove);


    Последний раз редактировалось: danbst (Пт Май 08, 2009 12:46 am), всего редактировалось 1 раз(а)

    MuTaToR

    Сообщения : 11
    Очки : 15
    Дата регистрации : 2009-04-30

    Re: Пример скрипта ScriptDev2

    Сообщение автор MuTaToR в Ср Май 06, 2009 9:14 pm

    Русские коментарии не помешали бы.
    avatar
    BonDit

    Сообщения : 3
    Очки : 3
    Дата регистрации : 2009-06-02
    Возраст : 33

    Re: Пример скрипта ScriptDev2

    Сообщение автор BonDit в Вт Июн 02, 2009 5:18 pm

    Надеюсь эта тема будет поддерживаться, лично я сейчас получил кучу новой и довольно нужной для себя информации, спасибо что делаете такое!
    avatar
    KiriX
    Admin
    Admin

    Сообщения : 42
    Очки : 60
    Дата регистрации : 2009-04-15
    Возраст : 32
    Откуда : Петрозаводск

    Re: Пример скрипта ScriptDev2

    Сообщение автор KiriX в Вт Июн 09, 2009 8:39 pm

    BonDit пишет:Надеюсь эта тема будет поддерживаться, лично я сейчас получил кучу новой и довольно нужной для себя информации, спасибо что делаете такое!
    К сожалению, я сейчас очень занят, однако, как только разберусь с дипломом, буду здесь появляться чазе и буду стараться дозаполнять форум.
    Но, требуется помощь, заполнение подобного форума не может быть возложено на одного человека, тем более, самого новичка в коде =)
    avatar
    BonDit

    Сообщения : 3
    Очки : 3
    Дата регистрации : 2009-06-02
    Возраст : 33

    Re: Пример скрипта ScriptDev2

    Сообщение автор BonDit в Ср Июн 24, 2009 6:37 pm

    Не подскажите как описать мобу выход из боя, если игроки его отвели скажем на 30 ярдов от точки спавна? В конфиг мангоса не посылать, пробывал, такое работает только на не скриптованных мобах, те же мобы кот скриптованы в SD2, будут ходить за ними пока агро не слетит.
    avatar
    Arhangeldie

    Сообщения : 1
    Очки : 1
    Дата регистрации : 2009-06-25
    Возраст : 28
    Откуда : Russia

    Re: Пример скрипта ScriptDev2

    Сообщение автор Arhangeldie в Чт Июн 25, 2009 10:58 am

    Не могу разоратся с этим.../--HP SAY
    Код:
     if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 75)
     {
     DoScriptText(SAY_LOKEN_75, m_creature);
    }
    это в  void UpdateAI(const uint32 diff), как видно пытаюся написать скрипт на Локена, но когда его уровень жизни доходит до 75% он начинает спамить в чат без остановки, у него ещё есть фаза на 50% и там 2 спама =), не могли бы подсказать как эту фунцию обработать что бы он после выполнения  
    Код:
     if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 75)
     {
     DoScriptText(SAY_LOKEN_75, m_creature);
    }
    больше не выполнял эту функцию.

    Imprtat

    Сообщения : 1
    Очки : 1
    Дата регистрации : 2009-07-13

    Re: Пример скрипта ScriptDev2

    Сообщение автор Imprtat в Пн Июл 13, 2009 2:17 am

    Arhangeldie пишет:Не могу разоратся с этим.../--HP SAY
    Код:
     if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 75)
     {
     DoScriptText(SAY_LOKEN_75, m_creature);
    }
    это в void UpdateAI(const uint32 diff), как видно пытаюся написать скрипт на Локена, но когда его уровень жизни доходит до 75% он начинает спамить в чат без остановки, у него ещё есть фаза на 50% и там 2 спама =), не могли бы подсказать как эту фунцию обработать что бы он после выполнения
    Код:
     if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 75)
     {
     DoScriptText(SAY_LOKEN_75, m_creature);
    }
    больше не выполнял эту функцию.
    сначало проверь меньше ли у боса 50% хп, если нет на 75%

    maxmouse

    Сообщения : 3
    Очки : 3
    Дата регистрации : 2009-07-26
    Возраст : 26
    Откуда : Калининград

    Re: Пример скрипта ScriptDev2

    Сообщение автор maxmouse в Вс Июл 26, 2009 1:47 am

    у меня есть несколько вопросов по scriptdev2:
    1) в void UpdateAI(const uint32 uiDiff) - uiDiff это просто хм... что-то типа таймера? ну то есть функция UpdateAI вызывается предположим каждую миллисекунду с параметром, увеличивающимся на 1? или это время в миллисекундах между двумя вызовами функции?
    2) предположим я дописал скрипт в исходниках скриптдева. что бы он работал в игре, мне нужно просто скомпилировать скриптдев и перекинуть полученные файлы в директорию с ядром или нужно еще что либо?

    maxmouse

    Сообщения : 3
    Очки : 3
    Дата регистрации : 2009-07-26
    Возраст : 26
    Откуда : Калининград

    Re: Пример скрипта ScriptDev2

    Сообщение автор maxmouse в Вс Июл 26, 2009 1:52 am

    Arhangeldie пишет:Не могу разоратся с этим.../--HP SAY
    Код:
     if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 75)
     {
     DoScriptText(SAY_LOKEN_75, m_creature);
    }
    это в  void UpdateAI(const uint32 diff), как видно пытаюся написать скрипт на Локена, но когда его уровень жизни доходит до 75% он начинает спамить в чат без остановки, у него ещё есть фаза на 50% и там 2 спама =), не могли бы подсказать как эту фунцию обработать что бы он после выполнения  
    Код:
     if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 75)
     {
     DoScriptText(SAY_LOKEN_75, m_creature);
    }
    больше не выполнял эту функцию.

    насколько я понял, автору нужно чтобы локен говорил каждую фразу только один раз.
    имхо решение таково: нужно добавить две bool переменных и переписать условие:
    Код:
    bool scripttextsaid75=false;
    bool scripttextsaid50=false;
    if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50&&!scripttextsaid50)
    {
    DoScriptText(SAY_LOKEN_75, m_creature);
    scripttextsaid50=true;
    }
    else if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 75&&!scripttextsaid75)
    {
     DoScriptText(SAY_LOKEN_75, m_creature);
     scripttextsaid75=true;
    }
    как то такSmile

    MuTaToR

    Сообщения : 11
    Очки : 15
    Дата регистрации : 2009-04-30

    Re: Пример скрипта ScriptDev2

    Сообщение автор MuTaToR в Вт Сен 15, 2009 11:48 pm

    Помогите зделать патч, чтоб спел не стакался(не скалдывался =) ), у орка есть спел коорый кастуется и стакается, а стакаться недолжен.
    avatar
    KiriX
    Admin
    Admin

    Сообщения : 42
    Очки : 60
    Дата регистрации : 2009-04-15
    Возраст : 32
    Откуда : Петрозаводск

    Re: Пример скрипта ScriptDev2

    Сообщение автор KiriX в Пт Сен 18, 2009 12:16 am

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

    MuTaToR

    Сообщения : 11
    Очки : 15
    Дата регистрации : 2009-04-30

    Re: Пример скрипта ScriptDev2

    Сообщение автор MuTaToR в Пт Сен 25, 2009 3:52 pm

    KiriX пишет:
    MuTaToR пишет:Помогите зделать патч, чтоб спел не стакался(не скалдывался =) ), у орка есть спел коорый кастуется и стакается, а стакаться недолжен.
    Это к скриптам никакого отношения не имеет...
    Я хотел в раздел учимся писать патч кинуть, но сильно промахнулся Shocked

    Crayzi

    Сообщения : 1
    Очки : 1
    Дата регистрации : 2009-12-09

    Re: Пример скрипта ScriptDev2

    Сообщение автор Crayzi в Ср Дек 09, 2009 4:19 am

    Может кто знает, скриптовые квэсты реализуются через скрипт дэв или через ядро, и я бы не отказался рассмотреть по подробнее эту тему, мне она очень интересна.

    MuTaToR

    Сообщения : 11
    Очки : 15
    Дата регистрации : 2009-04-30

    Re: Пример скрипта ScriptDev2

    Сообщение автор MuTaToR в Ср Дек 09, 2009 5:49 pm

    Нерабочие квесты чинятся через ScriptDev2

    Спонсируемый контент

    Re: Пример скрипта ScriptDev2

    Сообщение автор Спонсируемый контент


      Текущее время Вс Ноя 18, 2018 2:37 am