在战斗中,经常需要指挥让PlayerBot跑位,如果都是玩家当然可以听YY指挥,但是PlayerBot和NPCBot可没有办法。因此有个想法,就是在战斗指挥PlayerBot或者NPCBot跑位。
先说说我的思路,刚开始的想法是Ctrl+鼠标右键来设定PlayerBot/NPCBot的目的点。发现魔兽客户端只提供了GetCursorPosition()能获取x,y值,但Cursor的坐标体系是基于屏幕分辨率的,而不是后台地图的坐标体系。这条路走不通。
突然想到了一个东西,暴风雪技能以及照明弹技能,这种技能是点了之后会用鼠标选中区域,这个区域信息在后台后传入参数SpellCastTargets,里面带着目标点的地图坐标。你说让一个74或者德鲁伊学一个这种技能总不太好吧。而且暴风雪技能需要引导,照明弹时间CD太长,盗贼的扰乱需要潜行形态。于是我想到了烟幕弹,烟幕弹是物品,CD是5秒,但物品的CD是ItemTemplate表中可以改的(改完以后需要删除WDB缓存目录并重启客户端),而且烟幕弹的本质是关联了一个烟幕弹的法术,例如白色烟幕弹物品ID为23768,其表中spellid_1为30262,这是spell_dbc中一个叫白色烟幕弹的法术。扔这个烟幕弹的本质其实就是释放了这个30262的法术,大家可以.learn 30262试试看就知道了。
好了,这下思路清晰了,继续看后台如何实现,就是看使用物品是否有相对应的事件发送到后台,以AzerothCore为例,有个AllItemScript可以方便外接的类,里面有方法:
virtual bool CanItemUse(Player /player/, Item /item/, SpellCastTargets const& /targets/) { return false; }
注册一个自己的Script进去实现这个方法,在这个方法里就能获取到SpellCastTargets,里面的GetDstPos()就能返回WorldLocation对象,就有x,y值了,具体实现就不在这儿描述了。
我的设计是:
// 23768 白色烟雾弹 所有的Bots(除了T)跑位到该位置
// 23770 蓝色烟雾弹 所有的远程跑位到该位置
// 23771 绿色烟雾弹 所有的近战跑位到该位置
// 23769 红色烟雾弹 所有的T跑位到该位置
// 以上4中烟雾弹,如果你当前选择了某个Bot,那就只是指定该Bot跑位到该位置
// 25886 紫色烟雾弹 小队成员跑位专用的烟雾弹,如果选择某个Bot,则这个bot所在的小组跑位到该位置。如果没有选目标或者选择的目标是自己活着非BOT,那就是本小队的人都跑位到该位置
我在AzerothCore中集成了PlayerBot和NpcBot,就得实现了2个AllItemScript,分别用于实现PlayerBot和NPCBot的跑位。

    -- for NPCBot
  class NpcBotsAllItemScript : AllItemScript {
  public:
    NpcBotsAllItemScript() : AllItemScript("NpcBotsItemScript") {}
    bool CanItemUse(Player* player, Item* item, SpellCastTargets const& targets) {
        if (player && item && player->GetBotMgr()) {
            player->GetBotMgr()->OnUseItem(player, item, &targets);
        }
        return false;
    }
  };
  
  -- for PlayerBot
  class PlayerbotsItemScript : AllItemScript {
  public:
    PlayerbotsItemScript() : AllItemScript("PlayerBotsItemScript") { }
  
    bool CanItemUse(Player* player, Item* item, SpellCastTargets const& targets) {
        if (player && item) {
            if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
            {
                for (PlayerBotMap::const_iterator it = playerbotMgr->GetPlayerBotsBegin(); it != playerbotMgr->GetPlayerBotsEnd(); ++it)
                {
                    if (Player* const bot = it->second)
                    {
                        if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot)) {
                            botAI->OnUseItem(player, item, &targets);
                        }
                    }
                }
            }
            
        }
        return false;
    }
  };


标签: none