魔兽3.3.5版本AI模块代码拆分解析(魔兽3.3.5模块是状态机)

文章目录

    • 一、简介
      • 1)大怪物的AI主要涉及两个类:BossAI和WorldBossAI
      • 2)普通小怪的AI,基本继承类:ScriptedAI
      • 3)传奇怪物的AI,继承CreatureAI类
      • 4)人物AI,PlayerAI类
      • 5)PassiveAI(被动AI):
      • 6)PossessedAI(被占据AI):
      • 7)NullCreatureAI(空生物AI):
      • 8)CritterAI(小动物AI):
      • 9)TriggerAI(触发器AI)
      • 10)AggressorAI(攻击者AI):
      • 11)CombatAI(战斗AI):
      • 12)CasterAI(施法者AI):
      • 13)ArcherAI(弓箭手AI):
      • 14)TurretAI(炮塔AI):
      • 15)VehicleAI(载具AI):
      • 16)TotemAI (图腾AI)
      • 17)GuardAI(守卫AI)
      • 18)NullGameObjectAI(空游戏对象AI):
      • 19)GameObjectAI(游戏对象AI):
      • 20)SmartGameObjectAI(智能游戏对象AI):
    • 二、怪物类AI (ScriptedAI)
      • 1)jedoga_shadowseeker暗影追寻者副本怪物AI
        • (1)boss_jedoga_shadowseeker类
        • (2)npc_twilight_volunteer类
    • 三、GuardAI(守卫AI)
      • 1)平常守卫
        • (1)主要函数和类
      • 2)沙塔斯城守卫(Shattrath Faction)
        • (1)主要函数和类

本文是主讲怪物方向的AI

一、简介

1)大怪物的AI主要涉及两个类:BossAI和WorldBossAI

继承顺序

BossAIWorldBossAI都继承来自ScriptedAI类
ScriptedAI类继承来自CreatureAI类,
Creature类继承来自UnitAI类

②个例举例(继承BossAI)
<1>科林·狄尔布鲁(Coren Direbrew)

struct boss_coren_direbrew : public BossAI

魔兽3.3.5版本AI模块代码拆分解析(魔兽3.3.5模块是状态机)_第1张图片

<2>烟网女王(Mother Smolderweb)

struct boss_mother_smolderweb : public BossAI

魔兽3.3.5版本AI模块代码拆分解析(魔兽3.3.5模块是状态机)_第2张图片

<3>巨龙之王维姆萨拉克(Overlord Wyrmthalak)

struct boss_overlord_wyrmthalak : public BossAI

魔兽3.3.5版本AI模块代码拆分解析(魔兽3.3.5模块是状态机)_第3张图片

③WorldBossAI继承举例

1)Azuregos(艾索雷葛斯)
struct boss_azuregos : public WorldBossAI

魔兽3.3.5版本AI模块代码拆分解析(魔兽3.3.5模块是状态机)_第4张图片

2)翡翠龙(emerald_dragon)
struct emerald_dragonAI : public WorldBossAI

魔兽3.3.5版本AI模块代码拆分解析(魔兽3.3.5模块是状态机)_第5张图片

2)普通小怪的AI,基本继承类:ScriptedAI

①分别举例说明:
1)暮光志愿者AI

struct npc_twilight_volunteer : public ScriptedAI

魔兽3.3.5版本AI模块代码拆分解析(魔兽3.3.5模块是状态机)_第6张图片

2)Millhouse Manastorm(米尔豪斯·法力风暴)

struct npc_millhouse_manastorm : public ScriptedAI

魔兽3.3.5版本AI模块代码拆分解析(魔兽3.3.5模块是状态机)_第7张图片

3)传奇怪物的AI,继承CreatureAI类

①the lich king巫妖王的全部AI
魔兽3.3.5版本AI模块代码拆分解析(魔兽3.3.5模块是状态机)_第8张图片

②Valithria Dreamwalker (瓦莉瑟瑞娅·梦行者) 的全部AI
魔兽3.3.5版本AI模块代码拆分解析(魔兽3.3.5模块是状态机)_第9张图片

③Algalon the Observer(奥尔加隆,观察者之眼)
魔兽3.3.5版本AI模块代码拆分解析(魔兽3.3.5模块是状态机)_第10张图片

④Sister Svalna(斯瓦尔娜修女)

魔兽3.3.5版本AI模块代码拆分解析(魔兽3.3.5模块是状态机)_第11张图片

4)人物AI,PlayerAI类

5)PassiveAI(被动AI):

  • 说明
    PassiveAI类通常用于实现无攻击性的NPC或生物的行为。这些NPC通常不会主动攻击玩家或其他生物,而是表现出一种被动的行为,如漫游、站立、交谈等。PassiveAI类的目的是为了让这些NPC在游戏中营造出更真实、更丰富的环境。

6)PossessedAI(被占据AI):

  • 说明
    PossessedAI类用于实现被玩家控制的角色的行为。这些角色可以是玩家角色的宠物、召唤物或其他受玩家操控的单位。PossessedAI类的作用是让这些角色能够响应玩家的指令,并执行相应的行动和技能。

7)NullCreatureAI(空生物AI):

  • 说明
    NullCreatureAI类通常用于实现没有具体行为和功能的生物。这些生物可能只是作为环境装饰或背景元素存在,没有实际的交互或行为逻辑。NullCreatureAI类的作用是为这些生物提供一个空的AI实现,使其在游戏中存在但不参与实际的游戏机制。

8)CritterAI(小动物AI):

  • 说明
    CritterAI类用于实现小动物(Critter)的行为。小动物通常是一些无害的生物,如松鼠、兔子等。CritterAI类的目的是为这些小动物提供一些随机动作和行为,增加游戏世界的真实感和活力。

9)TriggerAI(触发器AI)

  • 说明
    监测游戏中的触发器或事件,并在满足特定条件时执行相应的行为。触发器可以是游戏中的特定区域、玩家的行动、特定时间点等。当触发器被激活时,TriggerAI会根据预设的条件和行为定义来决定角色或NPC的反应。

10)AggressorAI(攻击者AI):

  • 说明
    AggressorAI用于定义攻击性NPC的行为逻辑。这些NPC通常是敌对的角色,会主动寻找并攻击玩家或其他目标。AggressorAI负责定义NPC的攻击目标选择、攻击方式、技能使用等行为。它使NPC能够主动发起攻击并进行战斗。

11)CombatAI(战斗AI):

  • 说明
    CombatAI用于实现战斗相关的NPC行为逻辑。它与AggressorAI类似,但更广泛地适用于各种类型的战斗角色。CombatAI负责定义NPC在战斗中的行为,包括攻击、防御、移动、技能使用等。它使NPC能够在战斗中表现出合理的战术和行动。

12)CasterAI(施法者AI):

  • 说明
    CasterAI用于实现施法型NPC的行为逻辑。这些NPC通常使用法术或技能进行攻击。CasterAI负责定义NPC施法的选择和顺序,以及如何应对不同的战斗情况。它使NPC能够根据具体情况选择合适的法术或技能,并在战斗中以施法者的身份进行攻击。

13)ArcherAI(弓箭手AI):

  • 说明
    ArcherAI用于实现弓箭手类型的NPC的行为逻辑。这些NPC使用远程武器(如弓箭)进行攻击。ArcherAI负责定义NPC在战斗中的射击策略、目标选择和攻击方式。它使NPC能够以弓箭手的身份进行远程攻击,并采取合适的战术进行射击。

14)TurretAI(炮塔AI):

  • 说明
    TurretAI用于实现炮塔或防御设施的行为逻辑。这些炮塔通常是固定在特定位置上的防御装置,用于攻击敌人。TurretAI负责定义炮塔的目标选择、攻击方式和射击频率等行为。它使炮塔能够自动识别并攻击敌人,提供防御和控制区域的能力。

15)VehicleAI(载具AI):

  • 说明
    VehicleAI用于实现游戏中的载具(如飞机、坦克、船只等)的行为逻辑。VehicleAI负责定义载具的移动、攻击、防御等行为。它使载具能够根据玩家的操控或AI指令进行移动和战斗,并提供特定类型载具的独特功能和能力。

16)TotemAI (图腾AI)

  • 说明
    在游戏中,图腾通常代表着特殊的力量或能力,可能具有各种不同的效果,如增益效果、伤害效果、治疗效果等

17)GuardAI(守卫AI)

  • 说明
    管理和控制守卫角色在游戏中的行为和动作,确保它们有效地执行守卫任务。守卫角色通常被安排在特定位置或区域,负责保护该区域免受敌对角色或其他威胁的侵犯。

18)NullGameObjectAI(空游戏对象AI):

  • 说明
    NullGameObjectAI是一个在游戏中代表空或无效游戏对象的AI类。它通常用于处理游戏中可能出现的空对象或无效对象的情况。NullGameObjectAI的作用是提供一种处理这些情况的机制,以避免潜在的错误或异常情况。

19)GameObjectAI(游戏对象AI):

  • 说明
    GameObjectAI是一个通用的游戏对象AI类,用于管理和控制游戏中的普通游戏对象的行为和交互。它可以处理游戏对象的移动、碰撞、状态变化等方面的逻辑,并根据游戏规则和设计来控制游戏对象的行为。

20)SmartGameObjectAI(智能游戏对象AI):

  • 说明
    SmartGameObjectAI是一个更高级的游戏对象AI类,具有更复杂和智能化的行为和决策能力。它可以根据游戏环境和条件进行推理和决策,并采取相应的行动。智能游戏对象AI通常用于实现游戏中的敌对角色、队友角色或其他具有复杂行为的角色。

二、怪物类AI (ScriptedAI)

1)jedoga_shadowseeker暗影追寻者副本怪物AI

魔兽3.3.5版本AI模块代码拆分解析(魔兽3.3.5模块是状态机)_第12张图片
npc_twilight_volunteer和boss_jedoga_shadowseeker是作为两种怪物的AI注册在这个副本脚本里面

  • 副本事件枚举
enum JedogaEvents
{
    EVENT_INTRO_SAY = 1,      --表示介绍对话事件。
    EVENT_START_FIGHT_1,      --表示战斗开始事件 1
    EVENT_START_FIGHT_2,      --表示战斗开始事件 2
    EVENT_CYCLONE_STRIKE,     --表示飓风打击事件
    EVENT_LIGHTNING_BOLT,     --表示闪电箭事件
    EVENT_THUNDERSHOCK,       --表示雷霆震击事件
    EVENT_START_PHASE_TWO,    --表示第二阶段开始事件
    EVENT_FLY_DELAY,          --表示飞行延迟事件
    EVENT_END_PHASE_TWO,      --表示第二阶段结束事件
    EVENT_CHOOSE_VOLUNTEER,   --表示选择志愿者事件
    EVENT_SUMMON_VOLUNTEER    --表示召唤志愿者事件
};
  • boss阶段
enum JedogaPhases
{
    PHASE_INTRO = 0,
    PHASE_ONE,
    PHASE_TWO,
    PHASE_THREE
};
enum EncounterState
{
    NOT_STARTED   = 0,
    IN_PROGRESS   = 1,
    FAIL          = 2,
    DONE          = 3,  --副本机制结束
    SPECIAL       = 4,
    TO_BE_DECIDED = 5
};
NOT_STARTED (值为0): 表示战斗或遭遇尚未开始的状态。
IN_PROGRESS (值为1): 表示战斗或遭遇正在进行中的状态。
FAIL (值为2): 表示战斗或遭遇失败的状态。
DONE (值为3): 表示战斗或遭遇成功完成的状态。
SPECIAL (值为4): 表示战斗或遭遇的特殊状态。
TO_BE_DECIDED (值为5): 表示战斗或遭遇的状态尚待决定
(1)boss_jedoga_shadowseeker类
  • 总结共写了几种函数
1)构造函数
boss_jedoga_shadowseeker(Creature* creature) : BossAI(creature, DATA_JEDOGA_SHADOWSEEKER), _volunteerWork(true) { }
2)重写reset函数
void Reset() override
3)重写JustEngagedWith函数
void JustEngagedWith(Unit* who) override
4)重写EnterEvadeMode函数
void EnterEvadeMode(EvadeReason /*why*/) override
5)有obj死亡
void KilledUnit(Unit* Victim) override
6)boss死亡事件
void JustDied(Unit* /*killer*/) override
7)获取是否志愿者是否死亡数据
uint32 GetData(uint32 type) const override
8)伤害发生事件
void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
9)行动函数-处理对应行动
void DoAction(int32 action) override
10)召唤事件
void JustSummoned(Creature* summon) override
11)召唤物死亡事件
void SummonedCreatureDies(Creature* summon, Unit* killer) override
12)移动事件
void MovementInform(uint32 type, uint32 pointId) override
13)处理事件(每帧处理)
void UpdateAI(uint32 diff) override
  • 成员变量
private:
    bool _volunteerWork;
    GuidVector _volunteerGUIDS;
    ObjectGuid _selectedVolunteerGUID;
    GuidUnorderedSet _initiateGUIDS;

①团灭重置或是boss转阶段函数-reset

    //boss_jedoga_shadowseeker类的函数
    void Reset() override
    {
        _Reset();

        events.SetPhase(PHASE_INTRO);
        me->SetReactState(REACT_PASSIVE);

        std::list<TempSummon*> summoned;
        me->SummonCreatureGroup(SUMMON_GROUP_INITIATES, &summoned);
        for (TempSummon* value : summoned)
            _initiateGUIDS.insert(value->GetGUID());

        if (TempSummon* controller = me->SummonCreature(NPC_JEDOGA_CONTROLLER, JedogaControllerPositions[0], TEMPSUMMON_MANUAL_DESPAWN))
            controller->CastSpell(me, SPELL_BEAM_VISUAL_JEDOGA);
        if (TempSummon* controller = me->SummonCreature(NPC_JEDOGA_CONTROLLER, JedogaControllerPositions[1], TEMPSUMMON_MANUAL_DESPAWN))
            controller->CastSpell(me, SPELL_BEAM_VISUAL_JEDOGA);

        events.ScheduleEvent(EVENT_INTRO_SAY, Minutes(2), 0, PHASE_INTRO);
    }

void BossAI::_Reset()
{
    if (!me->IsAlive())
        return;

    me->SetCombatPulseDelay(0);
    me->ResetLootMode();
    events.Reset();
    summons.DespawnAll();
    scheduler.CancelAll();
    if (instance && instance->GetBossState(_bossId) != DONE)
        instance->SetBossState(_bossId, NOT_STARTED);
}

<1>std::list summoned;这里会将根据配置里面的怪物数量读取对应召唤物放到容器里面

<2>召唤两个怪物id为NPC_JEDOGA_CONTROLLER的怪物在位置0和位置1,然后这两个怪物释放光束技能(SPELL_BEAM_VISUAL_JEDOGA,这个两个怪物在调用unsummon后会被销毁)

        if (TempSummon* controller = me->SummonCreature(NPC_JEDOGA_CONTROLLER, JedogaControllerPositions[0], TEMPSUMMON_MANUAL_DESPAWN))
            controller->CastSpell(me, SPELL_BEAM_VISUAL_JEDOGA);
        if (TempSummon* controller = me->SummonCreature(NPC_JEDOGA_CONTROLLER, JedogaControllerPositions[1], TEMPSUMMON_MANUAL_DESPAWN))
            controller->CastSpell(me, SPELL_BEAM_VISUAL_JEDOGA);

<3> 启动定时器,每隔两分钟启动说话事件

-------事件注册
 events.ScheduleEvent(EVENT_INTRO_SAY, Minutes(2), 0, PHASE_INTRO);
 ------事件触发(如果boss状态是结束状态,那么副本结束,给场景玩家发送布教)
                 case EVENT_INTRO_SAY:
                    if (instance->GetBossState(DATA_PRINCE_TALDARAM) == DONE)
                        Talk(SAY_PREACHING);
                    events.Repeat(Minutes(2));
                    break;

②这可能是玩家进入某块boss视野的区域,处理 BOSS 与玩家或其他单位刚刚发生接触时的行为调用的函数

    void JustEngagedWith(Unit* who) override
    {
        me->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL);
        me->RemoveAurasDueToSpell(SPELL_RANDOM_LIGHTNING_VISUAL);
        me->SummonCreatureGroup(SUMMON_GROUP_WORSHIPPERS);

        BossAI::JustEngagedWith(who);
        Talk(SAY_AGGRO);
        events.SetPhase(PHASE_ONE);

        for (JedogaVolunteerPositionPair const& posPair : JedogaVolunteerSpotPositions)
        {
            if (TempSummon* volunteer = me->SummonCreature(NPC_TWILIGHT_VOLUNTEER, posPair.first, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3s))
            {
                volunteer->GetMotionMaster()->MovePoint(POINT_INITIAL_POSITION, posPair.second);
                _volunteerGUIDS.push_back(volunteer->GetGUID());
            }
        }
    }

<1>移除与 SPELL_SPHERE_VISUAL 相关的光环效果。
<2>移除与 SPELL_RANDOM_LIGHTNING_VISUAL 相关的光环效果。
<3>召唤一组崇拜者(worshippers)的生物
<4>触发一个攻击的语音对话(aggro)。
<5>设置 BOSS 的战斗阶段(phase)为第一阶段(PHASE_ONE)
<6>按照配置读取怪物id为NPC_TWILIGHT_VOLUNTEER的坐标,将怪物移动到目标地点

③逃跑触发的函数(销毁所有召唤物,然后设置boss状态为挑战失败)
_EnterEvadeMode里面会冷却boss所有技能,停止战斗状态,设置攻击目标为空,去除身上的buff

    void EnterEvadeMode(EvadeReason /*why*/) override
    {
        summons.DespawnAll();
        _EnterEvadeMode();
        _DespawnAtEvade(Seconds(15));
    }

④有obj被杀掉调用这个,如果被杀的是玩家,那么boss就说点嚣张的话

    void KilledUnit(Unit* Victim) override
    {
        if (Victim->GetTypeId() == TYPEID_PLAYER)
            Talk(SAY_SLAY);
    }

⑤boss被杀调用的事件

    void JustDied(Unit* /*killer*/) override
    {
        _JustDied();
        Talk(SAY_DEATH);
    }

⑥获得特定数据(志愿者还在工作就返回1)

    uint32 GetData(uint32 type) const override
    {
        if (type == DATA_VOLUNTEER_WORK)
            return _volunteerWork ? 1 : 0;

        return 0;
    }

⑦伤害发生调用的函数

  • 说明
    伤害发生的时候,如果boss伤害少于55%,而且boss处于第一阶段,
    那么
    <1>boss进入下阶段,
    <2>重置boss状态,
    <3>1s后开启事件2
    void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
    {
        if (HealthBelowPct(55) && events.IsInPhase(PHASE_ONE))
        {
            events.Reset();
            events.SetPhase(PHASE_TWO);
            events.ScheduleEvent(EVENT_START_PHASE_TWO, 1s);
        }
    }
    ---------------------------
阶段二事件:EVENT_START_PHASE_TWO
移动到特定地点,设置无敌状态,不能攻击玩家,移动到特定地点
                case EVENT_START_PHASE_TWO:
                    me->SetReactState(REACT_PASSIVE);
                    me->AttackStop();
                    me->InterruptNonMeleeSpells(true);
                    me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
                    me->GetMotionMaster()->MovePoint(POINT_PHASE_TWO, JedogaGroundPosition);
                    break;

⑧召唤事件
若召唤物是WORSHIPPER则让其处于跪倒状态

    void JustSummoned(Creature* summon) override
    {
        if (summon->GetEntry() == NPC_TWILIGHT_WORSHIPPER)
        {
            summon->SetStandState(UNIT_STAND_STATE_KNEEL);
            summons.Summon(summon);
            return;
        }

        BossAI::JustSummoned(summon);
    }

⑨召唤物死亡
<1>如果死亡的召唤物是初始的召唤物,boss释放SPELL_HOVER_FALL_1技能,1s后执行EVENT_START_FIGHT_1事件
<2>如果死亡的召唤物是志愿者召唤物,改变志愿者的工作状态,如果是阶段二则转变到阶段三,启动阶段二结束事件EVENT_END_PHASE_TWO

    void SummonedCreatureDies(Creature* summon, Unit* killer) override
    {
        if (summon->GetEntry() == NPC_TWILIGHT_INITIATE)
        {
            _initiateGUIDS.erase(summon->GetGUID());
            if (_initiateGUIDS.empty())
            {
                DoCastSelf(SPELL_HOVER_FALL_1);
                me->SetAnimTier(AnimTier::Ground);
                events.ScheduleEvent(EVENT_START_FIGHT_1, Seconds(1));
            }
        }
        else if (summon->GetEntry() == NPC_TWILIGHT_VOLUNTEER)
        {
            _volunteerWork = false;

            if (events.IsInPhase(PHASE_TWO))
            {
                events.SetPhase(PHASE_THREE);
                events.RescheduleEvent(EVENT_END_PHASE_TWO, Seconds(1));
            }

            events.RescheduleEvent(EVENT_SUMMON_VOLUNTEER, Seconds(10));
        }

        BossAI::SummonedCreatureDies(summon, killer);
    }

⑩移动事件
<1>若不是按照点移动或是按照特效移动(就是飞行特效)那就返回
<2>去除UNIT_FLAG_UNINTERACTIBLE标志
具体来说,当一个单位具有UNIT_FLAG_UNINTERACTIBLE标志时,其他单位或玩家无法与该单位进行交互。这意味着玩家无法与该单位进行对话、攻击、施放法术等互动行为
<3>boss设置REACT_AGGRESSIVE,当一个单位的行为反应状态设置为REACT_AGGRESSIVE时,该单位将主动攻击其他单位,即使这些单位没有主动攻击它。这意味着该单位会对附近的敌对单位发起攻击,并对它们进行战斗。
<4>循环释放技能

    void MovementInform(uint32 type, uint32 pointId) override
    {
        if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE)
            return;

        switch (pointId)
        {
            case POINT_GROUND:
            
                me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
                me->SetReactState(REACT_AGGRESSIVE);
                DoZoneInCombat();
                events.ScheduleEvent(EVENT_CYCLONE_STRIKE, 3s);
                events.ScheduleEvent(EVENT_LIGHTNING_BOLT, 7s);
                events.ScheduleEvent(EVENT_THUNDERSHOCK, 12s);
                break;
            case POINT_PHASE_TWO:
                events.ScheduleEvent(EVENT_FLY_DELAY, 2s);
                break;
            case POINT_PHASE_TWO_FLY:
                events.ScheduleEvent(EVENT_CHOOSE_VOLUNTEER, 2s);
                break;
            default:
                break;
        }
    }

十一、主逻辑处理(每帧处理对应事件)
<1>每帧调用UpdateAI,这里会把事件都执行一遍
<2>事件执行结束会调用DoMeleeAttackIfReady进行正反手近战普通攻击

    void UpdateAI(uint32 diff) override
    {
        if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO))
            return;

        events.Update(diff);

        if (me->HasUnitState(UNIT_STATE_CASTING))
            return;

        while (uint32 eventId = events.ExecuteEvent())
        {
            switch (eventId)
            {
                case EVENT_INTRO_SAY:
                    if (instance->GetBossState(DATA_PRINCE_TALDARAM) == DONE)
                        Talk(SAY_PREACHING);
                    events.Repeat(Minutes(2));
                    break;
                case EVENT_START_FIGHT_1:
                    me->RemoveAurasDueToSpell(SPELL_BEAM_VISUAL_JEDOGA);
                    events.ScheduleEvent(EVENT_START_FIGHT_2, Seconds(1));
                    break;
                case EVENT_START_FIGHT_2:
                    summons.DespawnEntry(NPC_JEDOGA_CONTROLLER);
                    me->SetDisableGravity(false);
                    me->GetMotionMaster()->MoveLand(POINT_GROUND, JedogaGroundPosition);
                    break;
                case EVENT_START_PHASE_TWO:
                    me->SetReactState(REACT_PASSIVE);
                    me->AttackStop();
                    me->InterruptNonMeleeSpells(true);
                    me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
                    me->GetMotionMaster()->MovePoint(POINT_PHASE_TWO, JedogaGroundPosition);
                    break;
                case EVENT_FLY_DELAY:
                    me->SetDisableGravity(true);
                    me->GetMotionMaster()->MoveTakeoff(POINT_PHASE_TWO_FLY, JedogaFlyPosition);
                    break;
                case EVENT_CHOOSE_VOLUNTEER:
                    if (TempSummon* controller = me->SummonCreature(NPC_JEDOGA_CONTROLLER, JedogaControllerPositions[2], TEMPSUMMON_MANUAL_DESPAWN))
                    {
                        me->SetFacingToObject(controller);
                        controller->CastSpell(controller, SPELL_SACRIFICE_VISUAL);
                    }

                    Talk(SAY_CHOOSE);

                    if (_volunteerGUIDS.empty())
                        break;

                    _selectedVolunteerGUID = Trinity::Containers::SelectRandomContainerElement(_volunteerGUIDS);
                    if (Creature* volunteer = ObjectAccessor::GetCreature(*me, _selectedVolunteerGUID))
                        volunteer->AI()->DoAction(ACTION_CHOSEN);
                    break;
                case EVENT_SUMMON_VOLUNTEER:
                {
                    uint32 pos = std::distance(_volunteerGUIDS.begin(), std::find(_volunteerGUIDS.begin(), _volunteerGUIDS.end(), _selectedVolunteerGUID));
                    if (pos < JedogaVolunteerSpotPositions.size())
                    {
                        JedogaVolunteerPositionPair const& posPair = JedogaVolunteerSpotPositions.at(pos);
                        if (TempSummon* volunteer = me->SummonCreature(NPC_TWILIGHT_VOLUNTEER, posPair.first, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3s))
                            volunteer->GetMotionMaster()->MovePoint(POINT_INITIAL_POSITION, posPair.second);
                    }
                    break;
                }
                case EVENT_END_PHASE_TWO:
                    summons.DespawnEntry(NPC_JEDOGA_CONTROLLER);
                    DoCastSelf(SPELL_HOVER_FALL_2);
                    me->SetDisableGravity(false);
                    me->GetMotionMaster()->MoveLand(POINT_GROUND, JedogaGroundPosition);
                    break;
                case EVENT_CYCLONE_STRIKE:
                    DoCastSelf(SPELL_CYCLONE_STRIKE);
                    events.Repeat(Seconds(15), Seconds(30));
                    break;
                case EVENT_LIGHTNING_BOLT:
                    if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
                        DoCast(target, SPELL_LIGHTNING_BOLT);
                    events.Repeat(Seconds(15), Seconds(30));
                    break;
                case EVENT_THUNDERSHOCK:
                    if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
                        DoCast(target, SPELL_THUNDERSHOCK);
                    events.Repeat(Seconds(15), Seconds(30));
                    break;
                default:
                    break;
            }

            if (me->HasUnitState(UNIT_STATE_CASTING))
                return;
        }

        DoMeleeAttackIfReady();
    }
(2)npc_twilight_volunteer类

三、GuardAI(守卫AI)

1)平常守卫

(1)主要函数和类
  • 主要类
struct npc_guard_generic : public GuardAI
  • 主要函数
1、构造函数
npc_guard_generic(Creature* creature) : GuardAI(creature)
2void Reset() override
3void DoReplyToTextEmote(uint32 emote)
4void ReceiveEmote(Player* player, uint32 textEmote) override
5void JustEngagedWith(Unit* who) override
6void UpdateAI(uint32 diff) override
  • 主要成员变量
private:
    TaskScheduler _scheduler;
    TaskScheduler _combatScheduler;

2)沙塔斯城守卫(Shattrath Faction)

(1)主要函数和类
  • 主要类
struct npc_guard_shattrath_faction: public GuardAI
  • 主要函数
1、构造函数
npc_guard_shattrath_faction(Creature* creature) : GuardAI(creature)
2、重置函数
void Reset() override
3、与单位交互(比如攻击、施法、交互等。)
void JustEngagedWith(Unit* /*who*/) override
4、每帧更新游戏逻辑
void UpdateAI(uint32 diff) override
5void ScheduleVanish()
  • 成员变量
private:
    TaskScheduler _scheduler;

你可能感兴趣的:(c++,游戏开发专栏,服务器,笔记)