mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
[New Rpg] Implement GO_INNKEEPER and NEAR_NPC status
This commit is contained in:
@@ -244,7 +244,9 @@ public:
|
||||
|
||||
creators["new rpg status update"] = &ActionContext::new_rpg_status_update;
|
||||
creators["new rpg go grind"] = &ActionContext::new_rpg_go_grind;
|
||||
creators["new rpg go innkeeper"] = &ActionContext::new_rpg_go_innkeeper;
|
||||
creators["new rpg move random"] = &ActionContext::new_rpg_move_random;
|
||||
creators["new rpg move npc"] = &ActionContext::new_rpg_move_npc;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -423,7 +425,9 @@ private:
|
||||
|
||||
static Action* new_rpg_status_update(PlayerbotAI* ai) { return new NewRpgStatusUpdateAction(ai); }
|
||||
static Action* new_rpg_go_grind(PlayerbotAI* ai) { return new NewRpgGoGrindAction(ai); }
|
||||
static Action* new_rpg_go_innkeeper(PlayerbotAI* ai) { return new NewRpgGoInnKeeperAction(ai); }
|
||||
static Action* new_rpg_move_random(PlayerbotAI* ai) { return new NewRpgMoveRandomAction(ai); }
|
||||
static Action* new_rpg_move_npc(PlayerbotAI* ai) { return new NewRpgMoveNpcAction(ai); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <cmath>
|
||||
|
||||
#include "NewRpgStrategy.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "PathGenerator.h"
|
||||
#include "Player.h"
|
||||
@@ -28,27 +29,45 @@ bool NewRpgStatusUpdateAction::Execute(Event event)
|
||||
{
|
||||
case NewRpgStatus::IDLE:
|
||||
{
|
||||
// // IDLE -> NEAR_NPC
|
||||
// if (!info.lastNearNpc || info.lastNearNpc + setNpcInterval < getMSTime() && urand(1, 100) <= 50)
|
||||
// {
|
||||
// info.lastNearNpc = getMSTime();
|
||||
// GuidVector possibleTargets = AI_VALUE(GuidVector, "possible rpg targets");
|
||||
// if (possibleTargets.empty())
|
||||
// break;
|
||||
// info.status = NewRpgStatus::NEAR_NPC;
|
||||
// }
|
||||
// IDLE -> GO_GRIND
|
||||
if (!info.lastGrind || info.lastGrind + setGrindInterval < getMSTime())
|
||||
uint32 roll = urand(1, 100);
|
||||
// IDLE -> NEAR_NPC
|
||||
// if ((!info.lastNearNpc || info.lastNearNpc + setNpcInterval < getMSTime()) && roll <= 30)
|
||||
if (roll <= 20)
|
||||
{
|
||||
info.lastNearNpc = getMSTime();
|
||||
GuidVector possibleTargets = AI_VALUE(GuidVector, "possible rpg targets");
|
||||
if (possibleTargets.empty())
|
||||
break;
|
||||
info.status = NewRpgStatus::NEAR_NPC;
|
||||
return true;
|
||||
}
|
||||
// IDLE -> GO_INNKEEPER
|
||||
if (bot->GetLevel() >= 6 && roll <= 30)
|
||||
{
|
||||
WorldPosition pos = SelectRandomInnKeeperPos();
|
||||
if (pos == WorldPosition() || bot->GetExactDist(pos) < 50.0f)
|
||||
break;
|
||||
info.lastGoInnKeeper = getMSTime();
|
||||
info.status = NewRpgStatus::GO_INNKEEPER;
|
||||
info.innKeeperPos = pos;
|
||||
return true;
|
||||
}
|
||||
// IDLE -> GO_GRIND
|
||||
if (roll <= 90)
|
||||
{
|
||||
info.lastGrind = getMSTime();
|
||||
WorldPosition pos = SelectRandomGrindPos();
|
||||
if (pos == WorldPosition())
|
||||
break;
|
||||
info.lastGoGrind = getMSTime();
|
||||
info.status = NewRpgStatus::GO_GRIND;
|
||||
info.grindPos = pos;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
// IDLE -> REST
|
||||
info.status = NewRpgStatus::REST;
|
||||
info.lastRest = getMSTime();
|
||||
bot->SetStandState(UNIT_STAND_STATE_SIT);
|
||||
return true;
|
||||
}
|
||||
case NewRpgStatus::GO_GRIND:
|
||||
{
|
||||
@@ -58,33 +77,62 @@ bool NewRpgStatusUpdateAction::Execute(Event event)
|
||||
if (bot->GetExactDist(originalPos) < 10.0f)
|
||||
{
|
||||
info.status = NewRpgStatus::NEAR_RANDOM;
|
||||
info.lastNearRandom = getMSTime();
|
||||
info.grindPos = WorldPosition();
|
||||
return true;
|
||||
}
|
||||
// just choose another grindPos
|
||||
if (!info.lastGrind || info.lastGrind + setGrindInterval < getMSTime())
|
||||
// // just choose another grindPos
|
||||
// if (!info.lastGoGrind || info.lastGoGrind + setGrindInterval < getMSTime())
|
||||
// {
|
||||
// WorldPosition pos = SelectRandomGrindPos();
|
||||
// if (pos == WorldPosition())
|
||||
// break;
|
||||
// info.status = NewRpgStatus::GO_GRIND;
|
||||
// info.lastGoGrind = getMSTime();
|
||||
// info.grindPos = pos;
|
||||
// return true;
|
||||
// }
|
||||
break;
|
||||
}
|
||||
case NewRpgStatus::GO_INNKEEPER:
|
||||
{
|
||||
WorldPosition& originalPos = info.innKeeperPos;
|
||||
assert(info.grindPos != WorldPosition());
|
||||
// GO_INNKEEPER -> NEAR_NPC
|
||||
if (bot->GetExactDist(originalPos) < 10.0f)
|
||||
{
|
||||
WorldPosition pos = SelectRandomGrindPos();
|
||||
if (pos == WorldPosition())
|
||||
break;
|
||||
info.status = NewRpgStatus::GO_GRIND;
|
||||
info.lastGrind = getMSTime();
|
||||
info.grindPos = pos;
|
||||
info.lastNearNpc = getMSTime();
|
||||
info.status = NewRpgStatus::NEAR_NPC;
|
||||
info.innKeeperPos = WorldPosition();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NewRpgStatus::NEAR_RANDOM:
|
||||
{
|
||||
// NEAR_RANDOM -> GO_GRIND
|
||||
if (!info.lastGrind || info.lastGrind + setGrindInterval < getMSTime())
|
||||
// NEAR_RANDOM -> IDLE
|
||||
if (info.lastNearRandom + statusNearRandomDuration < getMSTime())
|
||||
{
|
||||
WorldPosition pos = SelectRandomGrindPos();
|
||||
if (pos == WorldPosition())
|
||||
break;
|
||||
info.lastGrind = getMSTime();
|
||||
botAI->rpgInfo.status = NewRpgStatus::GO_GRIND;
|
||||
botAI->rpgInfo.grindPos = pos;
|
||||
info.status = NewRpgStatus::IDLE;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NewRpgStatus::NEAR_NPC:
|
||||
{
|
||||
if (info.lastNearNpc + statusNearNpcDuration < getMSTime())
|
||||
{
|
||||
info.status = NewRpgStatus::IDLE;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NewRpgStatus::REST:
|
||||
{
|
||||
// REST -> IDLE
|
||||
if (info.lastRest + statusRestDuration < getMSTime())
|
||||
{
|
||||
info.status = NewRpgStatus::IDLE;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@@ -131,6 +179,35 @@ WorldPosition NewRpgStatusUpdateAction::SelectRandomGrindPos()
|
||||
return dest;
|
||||
}
|
||||
|
||||
WorldPosition NewRpgStatusUpdateAction::SelectRandomInnKeeperPos()
|
||||
{
|
||||
const std::vector<WorldLocation>& locs = IsAlliance(bot->getRace())
|
||||
? sRandomPlayerbotMgr->allianceInnkeeperPerLevelCache[bot->GetLevel()]
|
||||
: sRandomPlayerbotMgr->hordeInnkeeperPerLevelCache[bot->GetLevel()];
|
||||
std::vector<WorldLocation> prepared_locs;
|
||||
for (auto& loc : locs)
|
||||
{
|
||||
if (bot->GetMapId() != loc.GetMapId())
|
||||
continue;
|
||||
|
||||
float range = bot->GetLevel() <= 5 ? 500.0f : 2500.0f;
|
||||
if (bot->GetExactDist(loc) < range)
|
||||
{
|
||||
prepared_locs.push_back(loc);
|
||||
}
|
||||
}
|
||||
WorldPosition dest;
|
||||
if (!prepared_locs.empty())
|
||||
{
|
||||
uint32 idx = urand(0, prepared_locs.size() - 1);
|
||||
dest = prepared_locs[idx];
|
||||
}
|
||||
LOG_INFO("playerbots", "[New Rpg] Bot {} select random inn keeper pos Map:{} X:{} Y:{} Z:{} ({} available in {})",
|
||||
bot->GetName(), dest.GetMapId(), dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(),
|
||||
prepared_locs.size(), locs.size());
|
||||
return dest;
|
||||
}
|
||||
|
||||
bool NewRpgGoFarAwayPosAction::MoveFarTo(WorldPosition dest)
|
||||
{
|
||||
float dis = bot->GetExactDist(dest);
|
||||
@@ -184,6 +261,8 @@ bool NewRpgGoFarAwayPosAction::MoveFarTo(WorldPosition dest)
|
||||
|
||||
bool NewRpgGoGrindAction::Execute(Event event) { return MoveFarTo(botAI->rpgInfo.grindPos); }
|
||||
|
||||
bool NewRpgGoInnKeeperAction::Execute(Event event) { return MoveFarTo(botAI->rpgInfo.innKeeperPos); }
|
||||
|
||||
bool NewRpgMoveRandomAction::Execute(Event event)
|
||||
{
|
||||
float distance = rand_norm() * moveStep;
|
||||
@@ -211,4 +290,76 @@ bool NewRpgMoveRandomAction::Execute(Event event)
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NewRpgMoveNpcAction::Execute(Event event)
|
||||
{
|
||||
NewRpgInfo& info = botAI->rpgInfo;
|
||||
if (!info.npcPos)
|
||||
{
|
||||
GuidVector possibleTargets = AI_VALUE(GuidVector, "possible rpg targets");
|
||||
if (possibleTargets.empty())
|
||||
return false;
|
||||
int idx = urand(0, possibleTargets.size() - 1);
|
||||
ObjectGuid guid = possibleTargets[idx];
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (unit)
|
||||
{
|
||||
info.npcPos = GuidPosition(unit);
|
||||
info.lastReachNpc = 0;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->GetDistance(info.npcPos) <= INTERACTION_DISTANCE)
|
||||
{
|
||||
if (!info.lastReachNpc)
|
||||
{
|
||||
info.lastReachNpc = getMSTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (info.lastReachNpc && info.lastReachNpc + stayTime > getMSTime())
|
||||
return false;
|
||||
|
||||
info.npcPos = GuidPosition();
|
||||
info.lastReachNpc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(info.npcPos);
|
||||
Unit* unit = botAI->GetUnit(info.npcPos);
|
||||
if (!unit)
|
||||
return false;
|
||||
float x = unit->GetPositionX();
|
||||
float y = unit->GetPositionY();
|
||||
float z = unit->GetPositionZ();
|
||||
float mapId = unit->GetMapId();
|
||||
float angle = 0.f;
|
||||
if (bot->IsWithinLOS(x, y, z))
|
||||
{
|
||||
if (!unit->isMoving())
|
||||
angle = unit->GetAngle(bot) + (M_PI * irand(-25, 25) / 100.0); // Closest 45 degrees towards the target
|
||||
else
|
||||
angle = unit->GetOrientation() +
|
||||
(M_PI * irand(-25, 25) / 100.0); // 45 degrees infront of target (leading it's movement)
|
||||
}
|
||||
else
|
||||
angle = 2 * M_PI * rand_norm(); // A circle around the target.
|
||||
|
||||
x += cos(angle) * INTERACTION_DISTANCE * rand_norm();
|
||||
y += sin(angle) * INTERACTION_DISTANCE * rand_norm();
|
||||
bool exact = true;
|
||||
if (!unit->GetMap()->CheckCollisionAndGetValidCoords(unit, unit->GetPositionX(), unit->GetPositionY(),
|
||||
unit->GetPositionZ(), x, y, z))
|
||||
{
|
||||
x = unit->GetPositionX();
|
||||
y = unit->GetPositionY();
|
||||
z = unit->GetPositionZ();
|
||||
exact = false;
|
||||
}
|
||||
return MoveTo(mapId, x, y, z, false, false, false, exact);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -21,9 +21,13 @@ public:
|
||||
NewRpgStatusUpdateAction(PlayerbotAI* botAI) : Action(botAI, "new rpg status update") {}
|
||||
bool Execute(Event event) override;
|
||||
protected:
|
||||
const int32 setGrindInterval = 5 * 60 * 1000;
|
||||
const int32 setNpcInterval = 5 * 60 * 1000;
|
||||
// const int32 setGrindInterval = 5 * 60 * 1000;
|
||||
// const int32 setNpcInterval = 1 * 60 * 1000;
|
||||
const int32 statusNearNpcDuration = 3 * 60 * 1000;
|
||||
const int32 statusNearRandomDuration = 3 * 60 * 1000;
|
||||
const int32 statusRestDuration = 1 * 60 * 1000;
|
||||
WorldPosition SelectRandomGrindPos();
|
||||
WorldPosition SelectRandomInnKeeperPos();
|
||||
};
|
||||
|
||||
class NewRpgGoFarAwayPosAction : public MovementAction
|
||||
@@ -45,6 +49,14 @@ public:
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class NewRpgGoInnKeeperAction : public NewRpgGoFarAwayPosAction
|
||||
{
|
||||
public:
|
||||
NewRpgGoInnKeeperAction(PlayerbotAI* botAI) : NewRpgGoFarAwayPosAction(botAI, "new rpg go innkeeper") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
|
||||
class NewRpgMoveRandomAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
@@ -54,4 +66,13 @@ protected:
|
||||
const float moveStep = 50.0f;
|
||||
};
|
||||
|
||||
class NewRpgMoveNpcAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
NewRpgMoveNpcAction(PlayerbotAI* botAI) : MovementAction(botAI, "new rpg move npcs") {}
|
||||
bool Execute(Event event) override;
|
||||
protected:
|
||||
const uint32 stayTime = 8 * 1000;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -188,7 +188,7 @@ bool FindCorpseAction::Execute(Event event)
|
||||
|
||||
if (!moved)
|
||||
{
|
||||
moved = botAI->DoSpecificAction("spirit healer");
|
||||
moved = botAI->DoSpecificAction("spirit healer", Event(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,15 @@ void NewRpgStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("go grind status", NextAction::array(0, new NextAction("new rpg go grind", 1.0f), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("go innkeeper status", NextAction::array(0, new NextAction("new rpg go innkeeper", 1.0f), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("near random status", NextAction::array(0, new NextAction("new rpg move random", 1.0f), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("near npc status", NextAction::array(0, new NextAction("new rpg move npc", 1.0f), nullptr)));
|
||||
}
|
||||
|
||||
void NewRpgStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
|
||||
@@ -20,16 +20,30 @@ enum class NewRpgStatus
|
||||
// Exploring nearby
|
||||
NEAR_RANDOM,
|
||||
NEAR_NPC,
|
||||
// Idling
|
||||
// Taking a break
|
||||
REST,
|
||||
// Initial status
|
||||
IDLE
|
||||
};
|
||||
|
||||
struct NewRpgInfo
|
||||
{
|
||||
NewRpgStatus status{NewRpgStatus::IDLE};
|
||||
// NewRpgStatus::GO_GRIND
|
||||
WorldPosition grindPos{};
|
||||
uint32 lastGrind{0};
|
||||
uint32 lastGoGrind{0};
|
||||
// NewRpgStatus::GO_INNKEEPER
|
||||
WorldPosition innKeeperPos{};
|
||||
uint32 lastGoInnKeeper{0};
|
||||
// NewRpgStatus::NEAR_NPC
|
||||
GuidPosition npcPos{};
|
||||
uint32 lastNearNpc{0};
|
||||
uint32 lastReachNpc{0};
|
||||
// NewRpgStatus::NEAR_RANDOM
|
||||
uint32 lastNearRandom{0};
|
||||
// NewRpgStatus::REST
|
||||
uint32 lastRest{0};
|
||||
|
||||
std::string ToString()
|
||||
{
|
||||
std::stringstream out;
|
||||
@@ -51,9 +65,14 @@ struct NewRpgInfo
|
||||
case NewRpgStatus::IDLE:
|
||||
out << "IDLE";
|
||||
break;
|
||||
case NewRpgStatus::REST:
|
||||
out << "REST";
|
||||
break;
|
||||
default:
|
||||
out << "UNKNOWN";
|
||||
}
|
||||
out << "\nGrindPos: " << grindPos.GetMapId() << " " << grindPos.GetPositionX() << " " << grindPos.GetPositionY() << " " << grindPos.GetPositionZ();
|
||||
out << "\nLastGrind: " << lastGrind;
|
||||
out << "\nlastGoGrind: " << lastGoGrind;
|
||||
return out.str();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -216,7 +216,9 @@ public:
|
||||
creators["rpg trade useful"] = &TriggerContext::rpg_trade_useful;
|
||||
creators["rpg duel"] = &TriggerContext::rpg_duel;
|
||||
creators["go grind status"] = &TriggerContext::go_grind_status;
|
||||
creators["go innkeeper status"] = &TriggerContext::go_innkeeper_status;
|
||||
creators["near random status"] = &TriggerContext::near_random_status;
|
||||
creators["near npc status"] = &TriggerContext::near_npc_status;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -407,7 +409,9 @@ private:
|
||||
static Trigger* rpg_trade_useful(PlayerbotAI* botAI) { return new RpgTradeUsefulTrigger(botAI); }
|
||||
static Trigger* rpg_duel(PlayerbotAI* botAI) { return new RpgDuelTrigger(botAI); }
|
||||
static Trigger* go_grind_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, NewRpgStatus::GO_GRIND); }
|
||||
static Trigger* go_innkeeper_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, NewRpgStatus::GO_INNKEEPER); }
|
||||
static Trigger* near_random_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, NewRpgStatus::NEAR_RANDOM); }
|
||||
static Trigger* near_npc_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, NewRpgStatus::NEAR_NPC); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user