mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Stay strategy improvement (#1072)
* - Stay Strategy work in combat and with RTSC * - Fixed summon with stay strategy * - Added new stay strategy support for chat commands
This commit is contained in:
@@ -1105,9 +1105,9 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QueueChatResponse(
|
QueueChatResponse(ChatQueuedReply{msgtype, guid1.GetCounter(), guid2.GetCounter(), message,
|
||||||
ChatQueuedReply{msgtype, guid1.GetCounter(), guid2.GetCounter(), message, chanName,
|
chanName, name,
|
||||||
name, time(nullptr) + urand(inCombat ? 10 : 5, inCombat ? 25 : 15)});
|
time(nullptr) + urand(inCombat ? 10 : 5, inCombat ? 25 : 15)});
|
||||||
GetAiObjectContext()->GetValue<time_t>("last said", "chat")->Set(time(0) + urand(5, 25));
|
GetAiObjectContext()->GetValue<time_t>("last said", "chat")->Set(time(0) + urand(5, 25));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1244,10 +1244,10 @@ void PlayerbotAI::ChangeEngine(BotState type)
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case BOT_STATE_COMBAT:
|
case BOT_STATE_COMBAT:
|
||||||
// LOG_DEBUG("playerbots", "=== {} COMBAT ===", bot->GetName().c_str());
|
ChangeEngineOnCombat();
|
||||||
break;
|
break;
|
||||||
case BOT_STATE_NON_COMBAT:
|
case BOT_STATE_NON_COMBAT:
|
||||||
// LOG_DEBUG("playerbots", "=== {} NON-COMBAT ===", bot->GetName().c_str());
|
ChangeEngineOnNonCombat();
|
||||||
break;
|
break;
|
||||||
case BOT_STATE_DEAD:
|
case BOT_STATE_DEAD:
|
||||||
// LOG_DEBUG("playerbots", "=== {} DEAD ===", bot->GetName().c_str());
|
// LOG_DEBUG("playerbots", "=== {} DEAD ===", bot->GetName().c_str());
|
||||||
@@ -1258,6 +1258,23 @@ void PlayerbotAI::ChangeEngine(BotState type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlayerbotAI::ChangeEngineOnCombat()
|
||||||
|
{
|
||||||
|
if (HasStrategy("stay", BOT_STATE_COMBAT))
|
||||||
|
{
|
||||||
|
aiObjectContext->GetValue<PositionInfo>("pos", "stay")
|
||||||
|
->Set(PositionInfo(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerbotAI::ChangeEngineOnNonCombat()
|
||||||
|
{
|
||||||
|
if (HasStrategy("stay", BOT_STATE_NON_COMBAT))
|
||||||
|
{
|
||||||
|
aiObjectContext->GetValue<PositionInfo>("pos", "stay")->Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PlayerbotAI::DoNextAction(bool min)
|
void PlayerbotAI::DoNextAction(bool min)
|
||||||
{
|
{
|
||||||
if (!bot->IsInWorld() || bot->IsBeingTeleported() || (GetMaster() && GetMaster()->IsBeingTeleported()))
|
if (!bot->IsInWorld() || bot->IsBeingTeleported() || (GetMaster() && GetMaster()->IsBeingTeleported()))
|
||||||
@@ -2848,7 +2865,6 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell,
|
|||||||
if (!target)
|
if (!target)
|
||||||
target = bot;
|
target = bot;
|
||||||
|
|
||||||
|
|
||||||
if (Pet* pet = bot->GetPet())
|
if (Pet* pet = bot->GetPet())
|
||||||
if (pet->HasSpell(spellid))
|
if (pet->HasSpell(spellid))
|
||||||
return true;
|
return true;
|
||||||
@@ -3041,8 +3057,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, GameObject* goTarget, bool checkH
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerbotAI::CanCastSpell(uint32 spellid, float x, float y, float z, bool checkHasSpell,
|
bool PlayerbotAI::CanCastSpell(uint32 spellid, float x, float y, float z, bool checkHasSpell, Item* itemTarget)
|
||||||
Item* itemTarget)
|
|
||||||
{
|
{
|
||||||
if (!spellid)
|
if (!spellid)
|
||||||
return false;
|
return false;
|
||||||
@@ -4296,8 +4311,8 @@ bool PlayerbotAI::AllowActive(ActivityType activityType)
|
|||||||
mod = AutoScaleActivity(mod);
|
mod = AutoScaleActivity(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 ActivityNumber = GetFixedBotNumer(100,
|
uint32 ActivityNumber =
|
||||||
sPlayerbotAIConfig->botActiveAlone * static_cast<float>(mod) / 100 * 0.01f);
|
GetFixedBotNumer(100, sPlayerbotAIConfig->botActiveAlone * static_cast<float>(mod) / 100 * 0.01f);
|
||||||
|
|
||||||
return ActivityNumber <=
|
return ActivityNumber <=
|
||||||
(sPlayerbotAIConfig->botActiveAlone * mod) /
|
(sPlayerbotAIConfig->botActiveAlone * mod) /
|
||||||
@@ -4356,7 +4371,8 @@ void PlayerbotAI::RemoveShapeshift()
|
|||||||
RemoveAura("moonkin form");
|
RemoveAura("moonkin form");
|
||||||
RemoveAura("travel form");
|
RemoveAura("travel form");
|
||||||
RemoveAura("cat form");
|
RemoveAura("cat form");
|
||||||
RemoveAura("flight form"); bot->RemoveAura(33943); // The latter added for now as RemoveAura("flight form") currently does not work.
|
RemoveAura("flight form");
|
||||||
|
bot->RemoveAura(33943); // The latter added for now as RemoveAura("flight form") currently does not work.
|
||||||
RemoveAura("swift flight form");
|
RemoveAura("swift flight form");
|
||||||
RemoveAura("aquatic form");
|
RemoveAura("aquatic form");
|
||||||
RemoveAura("ghost wolf");
|
RemoveAura("ghost wolf");
|
||||||
@@ -4943,11 +4959,9 @@ Item* PlayerbotAI::FindAmmo() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Search inventory for the correct ammo type
|
// Search inventory for the correct ammo type
|
||||||
return FindItemInInventory([requiredAmmoType](ItemTemplate const* pItemProto) -> bool
|
return FindItemInInventory(
|
||||||
{
|
[requiredAmmoType](ItemTemplate const* pItemProto) -> bool
|
||||||
return pItemProto->Class == ITEM_CLASS_PROJECTILE &&
|
{ return pItemProto->Class == ITEM_CLASS_PROJECTILE && pItemProto->SubClass == requiredAmmoType; });
|
||||||
pItemProto->SubClass == requiredAmmoType;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr; // No ranged weapon equipped
|
return nullptr; // No ranged weapon equipped
|
||||||
@@ -6178,9 +6192,10 @@ bool PlayerbotAI::IsHealingSpell(uint32 spellFamilyName, flag96 spellFalimyFlags
|
|||||||
return spellFalimyFlags & healingFlags;
|
return spellFalimyFlags & healingFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SpellFamilyNames PlayerbotAI::Class2SpellFamilyName(uint8 cls)
|
||||||
SpellFamilyNames PlayerbotAI::Class2SpellFamilyName(uint8 cls) {
|
{
|
||||||
switch (cls) {
|
switch (cls)
|
||||||
|
{
|
||||||
case CLASS_WARRIOR:
|
case CLASS_WARRIOR:
|
||||||
return SPELLFAMILY_WARRIOR;
|
return SPELLFAMILY_WARRIOR;
|
||||||
case CLASS_PALADIN:
|
case CLASS_PALADIN:
|
||||||
|
|||||||
@@ -392,6 +392,8 @@ public:
|
|||||||
void HandleMasterOutgoingPacket(WorldPacket const& packet);
|
void HandleMasterOutgoingPacket(WorldPacket const& packet);
|
||||||
void HandleTeleportAck();
|
void HandleTeleportAck();
|
||||||
void ChangeEngine(BotState type);
|
void ChangeEngine(BotState type);
|
||||||
|
void ChangeEngineOnCombat();
|
||||||
|
void ChangeEngineOnNonCombat();
|
||||||
void DoNextAction(bool minimal = false);
|
void DoNextAction(bool minimal = false);
|
||||||
virtual bool DoSpecificAction(std::string const name, Event event = Event(), bool silent = false,
|
virtual bool DoSpecificAction(std::string const name, Event event = Event(), bool silent = false,
|
||||||
std::string const qualifier = "");
|
std::string const qualifier = "");
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ public:
|
|||||||
creators["move to loot"] = &ActionContext::move_to_loot;
|
creators["move to loot"] = &ActionContext::move_to_loot;
|
||||||
creators["open loot"] = &ActionContext::open_loot;
|
creators["open loot"] = &ActionContext::open_loot;
|
||||||
creators["guard"] = &ActionContext::guard;
|
creators["guard"] = &ActionContext::guard;
|
||||||
|
creators["return to stay position"] = &ActionContext::return_to_stay_position;
|
||||||
creators["move out of enemy contact"] = &ActionContext::move_out_of_enemy_contact;
|
creators["move out of enemy contact"] = &ActionContext::move_out_of_enemy_contact;
|
||||||
creators["set facing"] = &ActionContext::set_facing;
|
creators["set facing"] = &ActionContext::set_facing;
|
||||||
creators["set behind"] = &ActionContext::set_behind;
|
creators["set behind"] = &ActionContext::set_behind;
|
||||||
@@ -271,6 +272,7 @@ private:
|
|||||||
static Action* drop_target(PlayerbotAI* botAI) { return new DropTargetAction(botAI); }
|
static Action* drop_target(PlayerbotAI* botAI) { return new DropTargetAction(botAI); }
|
||||||
static Action* attack_duel_opponent(PlayerbotAI* botAI) { return new AttackDuelOpponentAction(botAI); }
|
static Action* attack_duel_opponent(PlayerbotAI* botAI) { return new AttackDuelOpponentAction(botAI); }
|
||||||
static Action* guard(PlayerbotAI* botAI) { return new GuardAction(botAI); }
|
static Action* guard(PlayerbotAI* botAI) { return new GuardAction(botAI); }
|
||||||
|
static Action* return_to_stay_position(PlayerbotAI* botAI) { return new ReturnToStayPositionAction(botAI); }
|
||||||
static Action* open_loot(PlayerbotAI* botAI) { return new OpenLootAction(botAI); }
|
static Action* open_loot(PlayerbotAI* botAI) { return new OpenLootAction(botAI); }
|
||||||
static Action* move_to_loot(PlayerbotAI* botAI) { return new MoveToLootAction(botAI); }
|
static Action* move_to_loot(PlayerbotAI* botAI) { return new MoveToLootAction(botAI); }
|
||||||
static Action* _return(PlayerbotAI* botAI) { return new ReturnAction(botAI); }
|
static Action* _return(PlayerbotAI* botAI) { return new ReturnAction(botAI); }
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "PositionValue.h"
|
#include "PositionValue.h"
|
||||||
|
|
||||||
void ReturnPositionResetAction::ResetReturnPosition()
|
void PositionsResetAction::ResetReturnPosition()
|
||||||
{
|
{
|
||||||
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
||||||
PositionInfo pos = posMap["return"];
|
PositionInfo pos = posMap["return"];
|
||||||
@@ -18,7 +18,7 @@ void ReturnPositionResetAction::ResetReturnPosition()
|
|||||||
posMap["return"] = pos;
|
posMap["return"] = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReturnPositionResetAction::SetReturnPosition(float x, float y, float z)
|
void PositionsResetAction::SetReturnPosition(float x, float y, float z)
|
||||||
{
|
{
|
||||||
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
||||||
PositionInfo pos = posMap["return"];
|
PositionInfo pos = posMap["return"];
|
||||||
@@ -26,6 +26,22 @@ void ReturnPositionResetAction::SetReturnPosition(float x, float y, float z)
|
|||||||
posMap["return"] = pos;
|
posMap["return"] = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PositionsResetAction::ResetStayPosition()
|
||||||
|
{
|
||||||
|
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
||||||
|
PositionInfo pos = posMap["stay"];
|
||||||
|
pos.Reset();
|
||||||
|
posMap["stay"] = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PositionsResetAction::SetStayPosition(float x, float y, float z)
|
||||||
|
{
|
||||||
|
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
||||||
|
PositionInfo pos = posMap["stay"];
|
||||||
|
pos.Set(x, y, z, botAI->GetBot()->GetMapId());
|
||||||
|
posMap["stay"] = pos;
|
||||||
|
}
|
||||||
|
|
||||||
bool FollowChatShortcutAction::Execute(Event event)
|
bool FollowChatShortcutAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Player* master = GetMaster();
|
Player* master = GetMaster();
|
||||||
@@ -34,7 +50,7 @@ bool FollowChatShortcutAction::Execute(Event event)
|
|||||||
|
|
||||||
// botAI->Reset();
|
// botAI->Reset();
|
||||||
botAI->ChangeStrategy("+follow,-passive,-grind,-move from group", BOT_STATE_NON_COMBAT);
|
botAI->ChangeStrategy("+follow,-passive,-grind,-move from group", BOT_STATE_NON_COMBAT);
|
||||||
botAI->ChangeStrategy("-follow,-passive,-grind,-move from group", BOT_STATE_COMBAT);
|
botAI->ChangeStrategy("-stay,-follow,-passive,-grind,-move from group", BOT_STATE_COMBAT);
|
||||||
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Reset();
|
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Reset();
|
||||||
|
|
||||||
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
||||||
@@ -42,6 +58,10 @@ bool FollowChatShortcutAction::Execute(Event event)
|
|||||||
pos.Reset();
|
pos.Reset();
|
||||||
posMap["return"] = pos;
|
posMap["return"] = pos;
|
||||||
|
|
||||||
|
pos = posMap["stay"];
|
||||||
|
pos.Reset();
|
||||||
|
posMap["stay"] = pos;
|
||||||
|
|
||||||
if (bot->IsInCombat())
|
if (bot->IsInCombat())
|
||||||
{
|
{
|
||||||
Formation* formation = AI_VALUE(Formation*, "formation");
|
Formation* formation = AI_VALUE(Formation*, "formation");
|
||||||
@@ -103,9 +123,10 @@ bool StayChatShortcutAction::Execute(Event event)
|
|||||||
|
|
||||||
botAI->Reset();
|
botAI->Reset();
|
||||||
botAI->ChangeStrategy("+stay,-passive,-move from group", BOT_STATE_NON_COMBAT);
|
botAI->ChangeStrategy("+stay,-passive,-move from group", BOT_STATE_NON_COMBAT);
|
||||||
botAI->ChangeStrategy("-follow,-passive,-move from group", BOT_STATE_COMBAT);
|
botAI->ChangeStrategy("+stay,-follow,-passive,-move from group", BOT_STATE_COMBAT);
|
||||||
|
|
||||||
SetReturnPosition(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ());
|
SetReturnPosition(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ());
|
||||||
|
SetStayPosition(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ());
|
||||||
|
|
||||||
botAI->TellMaster("Staying");
|
botAI->TellMaster("Staying");
|
||||||
return true;
|
return true;
|
||||||
@@ -133,10 +154,11 @@ bool FleeChatShortcutAction::Execute(Event event)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
botAI->Reset();
|
botAI->Reset();
|
||||||
botAI->ChangeStrategy("+follow,+passive", BOT_STATE_NON_COMBAT);
|
botAI->ChangeStrategy("+follow,-stay,+passive", BOT_STATE_NON_COMBAT);
|
||||||
botAI->ChangeStrategy("+follow,+passive", BOT_STATE_COMBAT);
|
botAI->ChangeStrategy("+follow,-stay,+passive", BOT_STATE_COMBAT);
|
||||||
|
|
||||||
ResetReturnPosition();
|
ResetReturnPosition();
|
||||||
|
ResetStayPosition();
|
||||||
|
|
||||||
if (bot->GetMapId() != master->GetMapId() || bot->GetDistance(master) > sPlayerbotAIConfig->sightDistance)
|
if (bot->GetMapId() != master->GetMapId() || bot->GetDistance(master) > sPlayerbotAIConfig->sightDistance)
|
||||||
{
|
{
|
||||||
@@ -155,10 +177,11 @@ bool GoawayChatShortcutAction::Execute(Event event)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
botAI->Reset();
|
botAI->Reset();
|
||||||
botAI->ChangeStrategy("+runaway", BOT_STATE_NON_COMBAT);
|
botAI->ChangeStrategy("+runaway,-stay", BOT_STATE_NON_COMBAT);
|
||||||
botAI->ChangeStrategy("+runaway", BOT_STATE_COMBAT);
|
botAI->ChangeStrategy("+runaway,-stay", BOT_STATE_COMBAT);
|
||||||
|
|
||||||
ResetReturnPosition();
|
ResetReturnPosition();
|
||||||
|
ResetStayPosition();
|
||||||
|
|
||||||
botAI->TellMaster("Running away");
|
botAI->TellMaster("Running away");
|
||||||
return true;
|
return true;
|
||||||
@@ -171,9 +194,10 @@ bool GrindChatShortcutAction::Execute(Event event)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
botAI->Reset();
|
botAI->Reset();
|
||||||
botAI->ChangeStrategy("+grind,-passive", BOT_STATE_NON_COMBAT);
|
botAI->ChangeStrategy("+grind,-passive,-stay", BOT_STATE_NON_COMBAT);
|
||||||
|
|
||||||
ResetReturnPosition();
|
ResetReturnPosition();
|
||||||
|
ResetStayPosition();
|
||||||
|
|
||||||
botAI->TellMaster("Grinding");
|
botAI->TellMaster("Grinding");
|
||||||
return true;
|
return true;
|
||||||
@@ -193,6 +217,7 @@ bool TankAttackChatShortcutAction::Execute(Event event)
|
|||||||
botAI->ChangeStrategy("-passive", BOT_STATE_COMBAT);
|
botAI->ChangeStrategy("-passive", BOT_STATE_COMBAT);
|
||||||
|
|
||||||
ResetReturnPosition();
|
ResetReturnPosition();
|
||||||
|
ResetStayPosition();
|
||||||
|
|
||||||
botAI->TellMaster("Attacking");
|
botAI->TellMaster("Attacking");
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -10,13 +10,15 @@
|
|||||||
|
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
|
|
||||||
class ReturnPositionResetAction : public Action
|
class PositionsResetAction : public Action
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ReturnPositionResetAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name) {}
|
PositionsResetAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name) {}
|
||||||
|
|
||||||
void ResetReturnPosition();
|
void ResetReturnPosition();
|
||||||
void SetReturnPosition(float x, float y, float z);
|
void SetReturnPosition(float x, float y, float z);
|
||||||
|
void ResetStayPosition();
|
||||||
|
void SetStayPosition(float x, float y, float z);
|
||||||
};
|
};
|
||||||
|
|
||||||
class FollowChatShortcutAction : public MovementAction
|
class FollowChatShortcutAction : public MovementAction
|
||||||
@@ -27,10 +29,10 @@ public:
|
|||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StayChatShortcutAction : public ReturnPositionResetAction
|
class StayChatShortcutAction : public PositionsResetAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StayChatShortcutAction(PlayerbotAI* botAI) : ReturnPositionResetAction(botAI, "stay chat shortcut") {}
|
StayChatShortcutAction(PlayerbotAI* botAI) : PositionsResetAction(botAI, "stay chat shortcut") {}
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
@@ -43,34 +45,34 @@ public:
|
|||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FleeChatShortcutAction : public ReturnPositionResetAction
|
class FleeChatShortcutAction : public PositionsResetAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FleeChatShortcutAction(PlayerbotAI* botAI) : ReturnPositionResetAction(botAI, "flee chat shortcut") {}
|
FleeChatShortcutAction(PlayerbotAI* botAI) : PositionsResetAction(botAI, "flee chat shortcut") {}
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GoawayChatShortcutAction : public ReturnPositionResetAction
|
class GoawayChatShortcutAction : public PositionsResetAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GoawayChatShortcutAction(PlayerbotAI* botAI) : ReturnPositionResetAction(botAI, "runaway chat shortcut") {}
|
GoawayChatShortcutAction(PlayerbotAI* botAI) : PositionsResetAction(botAI, "runaway chat shortcut") {}
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GrindChatShortcutAction : public ReturnPositionResetAction
|
class GrindChatShortcutAction : public PositionsResetAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GrindChatShortcutAction(PlayerbotAI* botAI) : ReturnPositionResetAction(botAI, "grind chat shortcut") {}
|
GrindChatShortcutAction(PlayerbotAI* botAI) : PositionsResetAction(botAI, "grind chat shortcut") {}
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TankAttackChatShortcutAction : public ReturnPositionResetAction
|
class TankAttackChatShortcutAction : public PositionsResetAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TankAttackChatShortcutAction(PlayerbotAI* botAI) : ReturnPositionResetAction(botAI, "tank attack chat shortcut") {}
|
TankAttackChatShortcutAction(PlayerbotAI* botAI) : PositionsResetAction(botAI, "tank attack chat shortcut") {}
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -159,3 +159,25 @@ bool ReturnAction::isUseful()
|
|||||||
PositionInfo pos = context->GetValue<PositionMap&>("position")->Get()[qualifier];
|
PositionInfo pos = context->GetValue<PositionMap&>("position")->Get()[qualifier];
|
||||||
return pos.isSet() && AI_VALUE2(float, "distance", "position_random") > sPlayerbotAIConfig->followDistance;
|
return pos.isSet() && AI_VALUE2(float, "distance", "position_random") > sPlayerbotAIConfig->followDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ReturnToStayPositionAction::isPossible()
|
||||||
|
{
|
||||||
|
PositionMap& posMap = AI_VALUE(PositionMap&, "position");
|
||||||
|
PositionInfo stayPosition = posMap["stay"];
|
||||||
|
if (stayPosition.isSet())
|
||||||
|
{
|
||||||
|
const float distance = bot->GetDistance(stayPosition.x, stayPosition.y, stayPosition.z);
|
||||||
|
if (distance > sPlayerbotAIConfig->reactDistance)
|
||||||
|
{
|
||||||
|
botAI->TellMaster("The stay position is too far to return. I am going to stay where I am now");
|
||||||
|
|
||||||
|
// Set the stay position to current position
|
||||||
|
stayPosition.Set(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId());
|
||||||
|
posMap["stay"] = stayPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,6 +40,13 @@ public:
|
|||||||
GuardAction(PlayerbotAI* botAI) : MoveToPositionAction(botAI, "move to position", "guard") {}
|
GuardAction(PlayerbotAI* botAI) : MoveToPositionAction(botAI, "move to position", "guard") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ReturnToStayPositionAction : public MoveToPositionAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ReturnToStayPositionAction(PlayerbotAI* ai) : MoveToPositionAction(ai, "move to position", "stay") {}
|
||||||
|
virtual bool isPossible();
|
||||||
|
};
|
||||||
|
|
||||||
class SetReturnPositionAction : public Action
|
class SetReturnPositionAction : public Action
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ bool ReachTargetAction::Execute(Event event) { return ReachCombatTo(AI_VALUE(Uni
|
|||||||
|
|
||||||
bool ReachTargetAction::isUseful()
|
bool ReachTargetAction::isUseful()
|
||||||
{
|
{
|
||||||
|
// do not move while staying
|
||||||
|
if (botAI->HasStrategy("stay", botAI->GetState()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// do not move while casting
|
// do not move while casting
|
||||||
if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL) != nullptr)
|
if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL) != nullptr)
|
||||||
{
|
{
|
||||||
@@ -30,6 +36,12 @@ std::string const ReachTargetAction::GetTargetName() { return "current target";
|
|||||||
|
|
||||||
bool CastReachTargetSpellAction::isUseful()
|
bool CastReachTargetSpellAction::isUseful()
|
||||||
{
|
{
|
||||||
|
// do not move while staying
|
||||||
|
if (botAI->HasStrategy("stay", botAI->GetState()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "current target"),
|
return sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "current target"),
|
||||||
(distance + sPlayerbotAIConfig->contactDistance));
|
(distance + sPlayerbotAIConfig->contactDistance));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "RTSCValues.h"
|
#include "RTSCValues.h"
|
||||||
#include "RtscAction.h"
|
#include "RtscAction.h"
|
||||||
|
#include "PositionValue.h"
|
||||||
|
|
||||||
Creature* SeeSpellAction::CreateWps(Player* wpOwner, float x, float y, float z, float o, uint32 entry, Creature* lastWp,
|
Creature* SeeSpellAction::CreateWps(Player* wpOwner, float x, float y, float z, float o, uint32 entry, Creature* lastWp,
|
||||||
bool important)
|
bool important)
|
||||||
@@ -123,6 +124,15 @@ bool SeeSpellAction::MoveToSpell(WorldPosition& spellPosition, bool inFormation)
|
|||||||
if (inFormation)
|
if (inFormation)
|
||||||
SetFormationOffset(spellPosition);
|
SetFormationOffset(spellPosition);
|
||||||
|
|
||||||
|
if (botAI->HasStrategy("stay", botAI->GetState()))
|
||||||
|
{
|
||||||
|
PositionMap& posMap = AI_VALUE(PositionMap&, "position");
|
||||||
|
PositionInfo stayPosition = posMap["stay"];
|
||||||
|
|
||||||
|
stayPosition.Set(spellPosition.getX(), spellPosition.getY(), spellPosition.getZ(), spellPosition.getMapId());
|
||||||
|
posMap["stay"] = stayPosition;
|
||||||
|
}
|
||||||
|
|
||||||
if (bot->IsWithinLOS(spellPosition.getX(), spellPosition.getY(), spellPosition.getZ()))
|
if (bot->IsWithinLOS(spellPosition.getX(), spellPosition.getY(), spellPosition.getZ()))
|
||||||
return MoveNear(spellPosition.getMapId(), spellPosition.getX(), spellPosition.getY(), spellPosition.getZ(), 0);
|
return MoveNear(spellPosition.getMapId(), spellPosition.getX(), spellPosition.getY(), spellPosition.getZ(), 0);
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
#include "LastMovementValue.h"
|
#include "LastMovementValue.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
#include "PositionValue.h"
|
||||||
|
|
||||||
bool StayActionBase::Stay()
|
bool StayActionBase::Stay()
|
||||||
{
|
{
|
||||||
@@ -42,6 +43,17 @@ bool StayAction::Execute(Event event) { return Stay(); }
|
|||||||
|
|
||||||
bool StayAction::isUseful()
|
bool StayAction::isUseful()
|
||||||
{
|
{
|
||||||
|
// Check if the bots is in stay position
|
||||||
|
PositionInfo stayPosition = AI_VALUE(PositionMap&, "position")["stay"];
|
||||||
|
if (stayPosition.isSet())
|
||||||
|
{
|
||||||
|
const float distance = bot->GetDistance(stayPosition.x, stayPosition.y, stayPosition.z);
|
||||||
|
if (sPlayerbotAIConfig->followDistance)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// move from group takes priority over stay as it's added and removed automatically
|
// move from group takes priority over stay as it's added and removed automatically
|
||||||
// (without removing/adding stay)
|
// (without removing/adding stay)
|
||||||
if (botAI->HasStrategy("move from group", BOT_STATE_COMBAT) ||
|
if (botAI->HasStrategy("move from group", BOT_STATE_COMBAT) ||
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "GridNotifiersImpl.h"
|
#include "GridNotifiersImpl.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
#include "PositionValue.h"
|
||||||
|
|
||||||
bool UseMeetingStoneAction::Execute(Event event)
|
bool UseMeetingStoneAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
@@ -224,6 +225,16 @@ bool SummonAction::Teleport(Player* summoner, Player* player)
|
|||||||
player->GetMotionMaster()->Clear();
|
player->GetMotionMaster()->Clear();
|
||||||
AI_VALUE(LastMovement&, "last movement").clear();
|
AI_VALUE(LastMovement&, "last movement").clear();
|
||||||
player->TeleportTo(mapId, x, y, z, 0);
|
player->TeleportTo(mapId, x, y, z, 0);
|
||||||
|
|
||||||
|
if (botAI->HasStrategy("stay", botAI->GetState()))
|
||||||
|
{
|
||||||
|
PositionMap& posMap = AI_VALUE(PositionMap&, "position");
|
||||||
|
PositionInfo stayPosition = posMap["stay"];
|
||||||
|
|
||||||
|
stayPosition.Set(x,y, z, mapId);
|
||||||
|
posMap["stay"] = stayPosition;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,13 @@
|
|||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
|
void StayStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
|
{
|
||||||
|
triggers.push_back(new TriggerNode(
|
||||||
|
"return to stay position",
|
||||||
|
NextAction::array(0, new NextAction("return to stay position", ACTION_MOVE), nullptr)));
|
||||||
|
}
|
||||||
|
|
||||||
NextAction** StayStrategy::getDefaultActions() { return NextAction::array(0, new NextAction("stay", 1.0f), nullptr); }
|
NextAction** StayStrategy::getDefaultActions() { return NextAction::array(0, new NextAction("stay", 1.0f), nullptr); }
|
||||||
|
|
||||||
void SitStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void SitStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
|
|||||||
@@ -10,12 +10,13 @@
|
|||||||
|
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
|
|
||||||
class StayStrategy : public NonCombatStrategy
|
class StayStrategy : public Strategy
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StayStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) {}
|
StayStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||||
|
|
||||||
std::string const getName() override { return "stay"; }
|
std::string const getName() override { return "stay"; }
|
||||||
|
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||||
NextAction** getDefaultActions() override;
|
NextAction** getDefaultActions() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
#include "PositionValue.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
#include "TemporarySummon.h"
|
#include "TemporarySummon.h"
|
||||||
#include "ThreatMgr.h"
|
#include "ThreatMgr.h"
|
||||||
@@ -507,11 +508,22 @@ bool IsBehindTargetTrigger::IsActive()
|
|||||||
|
|
||||||
bool IsNotBehindTargetTrigger::IsActive()
|
bool IsNotBehindTargetTrigger::IsActive()
|
||||||
{
|
{
|
||||||
|
if (botAI->HasStrategy("stay", botAI->GetState()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
return target && !AI_VALUE2(bool, "behind", "current target");
|
return target && !AI_VALUE2(bool, "behind", "current target");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsNotFacingTargetTrigger::IsActive() { return !AI_VALUE2(bool, "facing", "current target"); }
|
bool IsNotFacingTargetTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (botAI->HasStrategy("stay", botAI->GetState()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !AI_VALUE2(bool, "facing", "current target");
|
||||||
|
}
|
||||||
|
|
||||||
bool HasCcTargetTrigger::IsActive()
|
bool HasCcTargetTrigger::IsActive()
|
||||||
{
|
{
|
||||||
@@ -599,6 +611,18 @@ bool NewPlayerNearbyTrigger::IsActive() { return AI_VALUE(ObjectGuid, "new playe
|
|||||||
|
|
||||||
bool CollisionTrigger::IsActive() { return AI_VALUE2(bool, "collision", "self target"); }
|
bool CollisionTrigger::IsActive() { return AI_VALUE2(bool, "collision", "self target"); }
|
||||||
|
|
||||||
|
bool ReturnToStayPositionTrigger::IsActive()
|
||||||
|
{
|
||||||
|
PositionInfo stayPosition = AI_VALUE(PositionMap&, "position")["stay"];
|
||||||
|
if (stayPosition.isSet())
|
||||||
|
{
|
||||||
|
const float distance = bot->GetDistance(stayPosition.x, stayPosition.y, stayPosition.z);
|
||||||
|
return distance > sPlayerbotAIConfig->followDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool GiveItemTrigger::IsActive()
|
bool GiveItemTrigger::IsActive()
|
||||||
{
|
{
|
||||||
return AI_VALUE2(Unit*, "party member without item", item) && AI_VALUE2(uint32, "item count", item);
|
return AI_VALUE2(Unit*, "party member without item", item) && AI_VALUE2(uint32, "item count", item);
|
||||||
|
|||||||
@@ -827,6 +827,14 @@ public:
|
|||||||
SitTrigger(PlayerbotAI* botAI) : StayTimeTrigger(botAI, sPlayerbotAIConfig->sitDelay, "sit") {}
|
SitTrigger(PlayerbotAI* botAI) : StayTimeTrigger(botAI, sPlayerbotAIConfig->sitDelay, "sit") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ReturnToStayPositionTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ReturnToStayPositionTrigger(PlayerbotAI* ai) : Trigger(ai, "return to stay position", 2) {}
|
||||||
|
|
||||||
|
virtual bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
class ReturnTrigger : public StayTimeTrigger
|
class ReturnTrigger : public StayTimeTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ public:
|
|||||||
{
|
{
|
||||||
creators["return"] = &TriggerContext::_return;
|
creators["return"] = &TriggerContext::_return;
|
||||||
creators["sit"] = &TriggerContext::sit;
|
creators["sit"] = &TriggerContext::sit;
|
||||||
|
creators["return to stay position"] = &TriggerContext::return_to_stay_position;
|
||||||
creators["collision"] = &TriggerContext::collision;
|
creators["collision"] = &TriggerContext::collision;
|
||||||
|
|
||||||
creators["timer"] = &TriggerContext::Timer;
|
creators["timer"] = &TriggerContext::Timer;
|
||||||
@@ -228,6 +229,7 @@ private:
|
|||||||
static Trigger* give_water(PlayerbotAI* botAI) { return new GiveWaterTrigger(botAI); }
|
static Trigger* give_water(PlayerbotAI* botAI) { return new GiveWaterTrigger(botAI); }
|
||||||
static Trigger* no_rti(PlayerbotAI* botAI) { return new NoRtiTrigger(botAI); }
|
static Trigger* no_rti(PlayerbotAI* botAI) { return new NoRtiTrigger(botAI); }
|
||||||
static Trigger* _return(PlayerbotAI* botAI) { return new ReturnTrigger(botAI); }
|
static Trigger* _return(PlayerbotAI* botAI) { return new ReturnTrigger(botAI); }
|
||||||
|
static Trigger* return_to_stay_position(PlayerbotAI* ai) { return new ReturnToStayPositionTrigger(ai); }
|
||||||
static Trigger* sit(PlayerbotAI* botAI) { return new SitTrigger(botAI); }
|
static Trigger* sit(PlayerbotAI* botAI) { return new SitTrigger(botAI); }
|
||||||
static Trigger* far_from_rpg_target(PlayerbotAI* botAI) { return new FarFromRpgTargetTrigger(botAI); }
|
static Trigger* far_from_rpg_target(PlayerbotAI* botAI) { return new FarFromRpgTargetTrigger(botAI); }
|
||||||
static Trigger* near_rpg_target(PlayerbotAI* botAI) { return new NearRpgTargetTrigger(botAI); }
|
static Trigger* near_rpg_target(PlayerbotAI* botAI) { return new NearRpgTargetTrigger(botAI); }
|
||||||
|
|||||||
@@ -63,3 +63,25 @@ bool PositionValue::Load(std::string const text)
|
|||||||
}
|
}
|
||||||
|
|
||||||
WorldPosition CurrentPositionValue::Calculate() { return WorldPosition(bot); }
|
WorldPosition CurrentPositionValue::Calculate() { return WorldPosition(bot); }
|
||||||
|
|
||||||
|
PositionInfo SinglePositionValue::Calculate()
|
||||||
|
{
|
||||||
|
PositionMap& posMap = AI_VALUE(PositionMap&, "position");
|
||||||
|
return posMap[getQualifier()];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinglePositionValue::Set(PositionInfo value)
|
||||||
|
{
|
||||||
|
PositionMap& posMap = AI_VALUE(PositionMap&, "position");
|
||||||
|
PositionInfo pos = posMap[getQualifier()];
|
||||||
|
pos = value;
|
||||||
|
posMap[getQualifier()] = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinglePositionValue::Reset()
|
||||||
|
{
|
||||||
|
PositionMap& posMap = AI_VALUE(PositionMap&, "position");
|
||||||
|
PositionInfo pos = posMap[getQualifier()];
|
||||||
|
pos.Reset();
|
||||||
|
posMap[getQualifier()] = pos;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#ifndef _PLAYERBOT_POSITIONVALUE_H
|
#ifndef _PLAYERBOT_POSITIONVALUE_H
|
||||||
#define _PLAYERBOT_POSITIONVALUE_H
|
#define _PLAYERBOT_POSITIONVALUE_H
|
||||||
|
|
||||||
|
#include "NamedObjectContext.h"
|
||||||
#include "TravelMgr.h"
|
#include "TravelMgr.h"
|
||||||
#include "Value.h"
|
#include "Value.h"
|
||||||
|
|
||||||
@@ -15,6 +16,10 @@ class PositionInfo
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PositionInfo() : valueSet(false), x(0), y(0), z(0), mapId(0) {}
|
PositionInfo() : valueSet(false), x(0), y(0), z(0), mapId(0) {}
|
||||||
|
PositionInfo(float x, float y, float z, uint32 mapId, bool valueSet = true)
|
||||||
|
: valueSet(valueSet), x(x), y(y), z(z), mapId(mapId)
|
||||||
|
{
|
||||||
|
}
|
||||||
PositionInfo(PositionInfo const& other)
|
PositionInfo(PositionInfo const& other)
|
||||||
: valueSet(other.valueSet), x(other.x), y(other.y), z(other.z), mapId(other.mapId)
|
: valueSet(other.valueSet), x(other.x), y(other.y), z(other.z), mapId(other.mapId)
|
||||||
{
|
{
|
||||||
@@ -72,4 +77,13 @@ public:
|
|||||||
WorldPosition Calculate() override;
|
WorldPosition Calculate() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SinglePositionValue : public CalculatedValue<PositionInfo>, public Qualified
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SinglePositionValue(PlayerbotAI* ai, std::string name = "pos") : CalculatedValue(ai, name), Qualified() {};
|
||||||
|
virtual PositionInfo Calculate() override;
|
||||||
|
virtual void Set(PositionInfo value) override;
|
||||||
|
virtual void Reset() override;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ public:
|
|||||||
creators["rti cc"] = &ValueContext::rti_cc;
|
creators["rti cc"] = &ValueContext::rti_cc;
|
||||||
creators["rti"] = &ValueContext::rti;
|
creators["rti"] = &ValueContext::rti;
|
||||||
creators["position"] = &ValueContext::position;
|
creators["position"] = &ValueContext::position;
|
||||||
|
creators["pos"] = &ValueContext::pos;
|
||||||
creators["current position"] = &ValueContext::current_position;
|
creators["current position"] = &ValueContext::current_position;
|
||||||
creators["threat"] = &ValueContext::threat;
|
creators["threat"] = &ValueContext::threat;
|
||||||
|
|
||||||
@@ -342,6 +343,7 @@ private:
|
|||||||
static UntypedValue* attackers(PlayerbotAI* botAI) { return new AttackersValue(botAI); }
|
static UntypedValue* attackers(PlayerbotAI* botAI) { return new AttackersValue(botAI); }
|
||||||
|
|
||||||
static UntypedValue* position(PlayerbotAI* botAI) { return new PositionValue(botAI); }
|
static UntypedValue* position(PlayerbotAI* botAI) { return new PositionValue(botAI); }
|
||||||
|
static UntypedValue* pos(PlayerbotAI* ai) { return new SinglePositionValue(ai); }
|
||||||
static UntypedValue* current_position(PlayerbotAI* botAI) { return new CurrentPositionValue(botAI); }
|
static UntypedValue* current_position(PlayerbotAI* botAI) { return new CurrentPositionValue(botAI); }
|
||||||
static UntypedValue* rti(PlayerbotAI* botAI) { return new RtiValue(botAI); }
|
static UntypedValue* rti(PlayerbotAI* botAI) { return new RtiValue(botAI); }
|
||||||
static UntypedValue* rti_cc(PlayerbotAI* botAI) { return new RtiCcValue(botAI); }
|
static UntypedValue* rti_cc(PlayerbotAI* botAI) { return new RtiCcValue(botAI); }
|
||||||
|
|||||||
Reference in New Issue
Block a user