Всем привет. Решил поделится информацией, как же все таки заскриптовать босса, моба на С++.
Как мы знаем есть два способа скриптовки NPC. Это ScriptedAI и соответственно BossAI.
На данном случае я предлагаю использовать способ ScriptedAI.
Для начала давайте с Вами определимся, какие способности будет использовать наш пациент?
Для данного примера я выбрал 2 спелла:
Далее узнаем каким образом используются данные спеллы? Прочитали, поняли они кастуются на весь рейд, тоесть используем функцию SELECT_TARGET_RANDOM. Но об этом чуть позже.
Итак, приступим:
Для удобства в коде принято называть все своими именами:
Обозначим наши спеллы, перечислив их через 'перечислитель' Enum
Code
enum BossSpells
{
SPELL_IMPALE = 56090,
SPELL_UNHOLYSHADOW = 57369,
};
Дальше можно приступать к непосредственному оформлению самого босса: для начала создадим его шапочку (укажем имя скрипта)
Создаем отдельный класс для нашего моба/босса, присвоим классу имя нашего моба/босса. Присвоим АИ и зарегистрируем ее.
Code
class boss_wowjp_manual : public CreatureScript
{
public:
boss_wowjp_manual() : CreatureScript("boss_wowjp_manual") { }
CreatureAI* GetAI(Creature* creature) const
{
return new boss_wowjp_manualAI (creature);
}
struct boss_wowjp_manualAI : public ScriptedAI
{
boss_wowjp_manualAI(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
}
InstanceScript* instance;
Дальше мы с Вами разберем, как же ему использовать выбранные спеллы? Например через таймер.
Давайте введем переменные, таймеры для кастов и присвоим им значение
Code
uint32 ImpaleTimer;
uint32 UnholyshadowTimer;
void Reset()
{
ImpaleTimer = 30000;
UnholyshadowTimer = 65000;
}
Время, используещеся в программировании исчисляется в милисекундах, то есть 30000мс это есть 30 секунд (1000мс=1с)
Code
void EnterCombat(Unit* /*who*/)
{
me->MonsterYell("Your death will come now!", LANG_UNIVERSAL, NULL);
}
void JustDied(Unit* /*pKiller*/)
{
me->MonsterYell("You have deceived me! My time will come ...", LANG_UNIVERSAL, NULL);
}
Давайте разберемся что к чему:
Quote
void EnterCombat(Unit* /*who*/) - условие, агро моба.
me->MonsterYell("Your death will come now!", LANG_UNIVERSAL, NULL); - дествие при выполнении предыдущего условия
"Your death will come now!" - реплика которую должен выкрикнуть наш пациент при агро. Можно вместо слов в кавычках использовать текст из БД, например (-25, LANG_UNIVERSAL, NULL)
LANG_UNIVERSAL - это язык, на котором должен наш босс/моб болтать, из названия думаю ясно что этот способ универсальный, то есть понимают его все.
Вторую часть кода расписывать не стану, думаю понятно, тут тоже самое за исключением условия - наш босс/моб умер.
Хотелось бы остановить внимание на язках, которые сипользуются в ТС :
Дальше нужно заскриптовать наши спеллы, обновление АИ.
Принцип действия данной части кода таков: Если таймер способности меньше или равен нулю, то кастуем спелл и обновляем. Если не выполено предыдушее условие - таймер ведет отстчет в обратную сторону.
Code
void UpdateAI(const uint32 diff)
{
if (ImpaleTimer <= diff)
{
if (Unit* target = SELECT_TARGET_RANDOM)
DoCast(target, SPELL_IMPALE);
ImpaleTimer = 30000;
} else ImpaleTimer -= diff;
if (UnholyshadowTimer <= diff)
{
if (Unit* target = SELECT_TARGET_RANDOM)
DoCast(target, SPELL_UNHOLYSHADOW);
UnholyshadowTimer = 65000;
} else UnholyshadowTimer -= diff;
DoMeleeAttackIfReady();
}
DoMeleeAttackIfReady(); - эта часть дает боссу/мобу бить обычными атаками, если данной части в коде не будет наш босс будет бегать за вами и бить только тогда, когда подойдет время каста.
Вот вприниципе и вся кодовая часть нашего босса/моба. Давайте теперь из этого всего соберем полный код:
Code
enum BossSpells
{
SPELL_IMPALE = 56090,
SPELL_UNHOLYSHADOW = 57369,
};
class boss_wowjp_manual : public CreatureScript
{
public:
boss_wowjp_manual() : CreatureScript("boss_wowjp_manual") { }
CreatureAI* GetAI(Creature* creature) const
{
return new boss_wowjp_manualAI (creature);
}
struct boss_wowjp_manualAI : public ScriptedAI
{
boss_wowjp_manualAI(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
}
InstanceScript* instance;
uint32 ImpaleTimer;
uint32 UnholyshadowTimer;
void Reset()
{
ImpaleTimer = 30000;
UnholyshadowTimer = 65000;
}
void EnterCombat(Unit* /*who*/)
{
me->MonsterYell("Your death will come now!", LANG_UNIVERSAL, NULL);
}
void JustDied(Unit* /*pKiller*/)
{
me->MonsterYell("You have deceived me! My time will come ...", LANG_UNIVERSAL, NULL);
}
void UpdateAI(const uint32 diff)
{
if (ImpaleTimer <= diff)
{
if (Unit* target = SELECT_TARGET_RANDOM)
DoCast(target, SPELL_IMPALE);
ImpaleTimer = 30000;
} else ImpaleTimer -= diff;
if (UnholyshadowTimer <= diff)
{
if (Unit* target = SELECT_TARGET_RANDOM)
DoCast(target, SPELL_UNHOLYSHADOW);
UnholyshadowTimer = 65000;
} else UnholyshadowTimer -= diff;
DoMeleeAttackIfReady();
}
};
};
void AddSC_boss_wowjp_manual()
{
new boss_wowjp_manual();
}
void AddSC_boss_wowjp_manual() - этим мы добавим загрузку скрипта в ядро.
Наш босс готов.
P.S. Если вдруг вы захотите его немного изменить, поменять спеллы то тогда это будет кстати:
Цель, которую выберет босс/моб для удара определяется следующим условием:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)
Также бывают и другие типы выбора цели:
Quote
SELECT_TARGET_RANDOM - цель выбирается случайно.
SELECT_TARGET_TOPAGGRO - выбирает юнита, который по аггрессии занимает позицию с начала.
SELECT_TARGET_BOTTOMAGGRO - выбирает юнита, который по аггрессии занимает позицию с конца.
SELECT_TARGET_NEAREST - выбирает юнита, который находится ближе всех.
SELECT_TARGET_FARTHEST - выбирает юнита, который находится дальше всех.
спс Dimitro за подсказку по двум последним способам.
Автор данного мануала: pulvik