Make make a full check before questgiver choose such as reputation (#1109)

This commit is contained in:
Yunfan Li
2025-03-26 20:47:46 +08:00
committed by GitHub
parent feb7bb8a8b
commit d9da6d942d
3 changed files with 141 additions and 10 deletions

View File

@@ -242,7 +242,7 @@ bool NewRpgMoveNpcAction::Execute(Event event)
} }
WorldObject* object = ObjectAccessor::GetWorldObject(*bot, info.near_npc.npcOrGo); WorldObject* object = ObjectAccessor::GetWorldObject(*bot, info.near_npc.npcOrGo);
if (object && bot->GetDistance(object) <= INTERACTION_DISTANCE) if (object && IsWithinInteractionDist(object))
{ {
if (!info.near_npc.lastReach) if (!info.near_npc.lastReach)
{ {

View File

@@ -247,6 +247,134 @@ bool NewRpgBaseAction::InteractWithNpcOrGameObjectForQuest(ObjectGuid guid)
return true; return true;
} }
bool NewRpgBaseAction::CanInteractWithQuestGiver(Object* questGiver)
{
// This is a variant of Player::CanInteractWithQuestGiver
// that removes the distance check and keeps all other checks
switch (questGiver->GetTypeId())
{
case TYPEID_UNIT:
{
ObjectGuid guid = questGiver->GetGUID();
uint32 npcflagmask = UNIT_NPC_FLAG_QUESTGIVER;
// unit checks
if (!guid)
return false;
if (!bot->IsInWorld())
return false;
if (bot->IsInFlight())
return false;
// exist (we need look pets also for some interaction (quest/etc)
Creature* creature = ObjectAccessor::GetCreatureOrPetOrVehicle(*bot, guid);
if (!creature)
return false;
// Deathstate checks
if (!bot->IsAlive() && !(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_VISIBLE_TO_GHOSTS))
return false;
// alive or spirit healer
if (!creature->IsAlive() && !(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_INTERACT_WHILE_DEAD))
return false;
// appropriate npc type
if (npcflagmask && !creature->HasNpcFlag(NPCFlags(npcflagmask)))
return false;
// not allow interaction under control, but allow with own pets
if (creature->GetCharmerGUID())
return false;
// xinef: perform better check
if (creature->GetReactionTo(bot) <= REP_UNFRIENDLY)
return false;
// pussywizard: many npcs have missing conditions for class training and rogue trainer can for eg. train dual wield to a shaman :/ too many to change in sql and watch in the future
// pussywizard: this function is not used when talking, but when already taking action (buy spell, reset talents, show spell list)
if (npcflagmask & (UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_TRAINER_CLASS) && creature->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS && !bot->IsClass((Classes)creature->GetCreatureTemplate()->trainer_class, CLASS_CONTEXT_CLASS_TRAINER))
return false;
return true;
}
case TYPEID_GAMEOBJECT:
{
ObjectGuid guid = questGiver->GetGUID();
GameobjectTypes type = GAMEOBJECT_TYPE_QUESTGIVER;
if (GameObject* go = bot->GetMap()->GetGameObject(guid))
{
if (go->GetGoType() == type)
{
// Players cannot interact with gameobjects that use the "Point" icon
if (go->GetGOInfo()->IconName == "Point")
{
return false;
}
return true;
}
}
return false;
}
// unused for now
// case TYPEID_PLAYER:
// return bot->IsAlive() && questGiver->ToPlayer()->IsAlive();
// case TYPEID_ITEM:
// return bot->IsAlive();
default:
break;
}
return false;
}
bool NewRpgBaseAction::IsWithinInteractionDist(Object* questGiver)
{
// This is a variant of Player::CanInteractWithQuestGiver
// that only keep the distance check
switch (questGiver->GetTypeId())
{
case TYPEID_UNIT:
{
ObjectGuid guid = questGiver->GetGUID();
// unit checks
if (!guid)
return false;
// exist (we need look pets also for some interaction (quest/etc)
Creature* creature = ObjectAccessor::GetCreatureOrPetOrVehicle(*bot, guid);
if (!creature)
return false;
if (!creature->IsWithinDistInMap(bot, INTERACTION_DISTANCE))
return false;
return true;
}
case TYPEID_GAMEOBJECT:
{
ObjectGuid guid = questGiver->GetGUID();
GameobjectTypes type = GAMEOBJECT_TYPE_QUESTGIVER;
if (GameObject* go = bot->GetMap()->GetGameObject(guid))
{
if (go->IsWithinDistInMap(bot))
{
return true;
}
}
return false;
}
// case TYPEID_PLAYER:
// return bot->IsAlive() && questGiver->ToPlayer()->IsAlive();
// case TYPEID_ITEM:
// return bot->IsAlive();
default:
break;
}
return false;
}
bool NewRpgBaseAction::AcceptQuest(Quest const* quest, ObjectGuid guid) bool NewRpgBaseAction::AcceptQuest(Quest const* quest, ObjectGuid guid)
{ {
WorldPacket p(CMSG_QUESTGIVER_ACCEPT_QUEST); WorldPacket p(CMSG_QUESTGIVER_ACCEPT_QUEST);
@@ -283,7 +411,7 @@ bool NewRpgBaseAction::TurnInQuest(Quest const* quest, ObjectGuid guid)
} }
else else
{ {
uint32 bestId = BestReward(quest); uint32 bestId = BestRewardIndex(quest);
p << bestId; p << bestId;
bot->GetSession()->HandleQuestgiverChooseRewardOpcode(p); bot->GetSession()->HandleQuestgiverChooseRewardOpcode(p);
} }
@@ -291,7 +419,7 @@ bool NewRpgBaseAction::TurnInQuest(Quest const* quest, ObjectGuid guid)
return true; return true;
} }
uint32 NewRpgBaseAction::BestReward(Quest const* quest) uint32 NewRpgBaseAction::BestRewardIndex(Quest const* quest)
{ {
ItemIds returnIds; ItemIds returnIds;
ItemUsage bestUsage = ITEM_USAGE_NONE; ItemUsage bestUsage = ITEM_USAGE_NONE;
@@ -486,7 +614,7 @@ ObjectGuid NewRpgBaseAction::ChooseNpcOrGameObjectToInteract(bool questgiverOnly
if (distanceLimit && bot->GetDistance(object) > distanceLimit) if (distanceLimit && bot->GetDistance(object) > distanceLimit)
continue; continue;
if (HasQuestToAcceptOrReward(object)) if (CanInteractWithQuestGiver(object) && HasQuestToAcceptOrReward(object))
{ {
if (!nearestObject || bot->GetExactDist(nearestObject) > bot->GetExactDist(object)) if (!nearestObject || bot->GetExactDist(nearestObject) > bot->GetExactDist(object))
nearestObject = object; nearestObject = object;
@@ -504,7 +632,7 @@ ObjectGuid NewRpgBaseAction::ChooseNpcOrGameObjectToInteract(bool questgiverOnly
if (distanceLimit && bot->GetDistance(object) > distanceLimit) if (distanceLimit && bot->GetDistance(object) > distanceLimit)
continue; continue;
if (HasQuestToAcceptOrReward(object)) if (CanInteractWithQuestGiver(object) && HasQuestToAcceptOrReward(object))
{ {
if (!nearestObject || bot->GetExactDist(nearestObject) > bot->GetExactDist(object)) if (!nearestObject || bot->GetExactDist(nearestObject) > bot->GetExactDist(object))
nearestObject = object; nearestObject = object;

View File

@@ -32,16 +32,19 @@ protected:
bool MoveRandomNear(float moveStep = 50.0f, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL); bool MoveRandomNear(float moveStep = 50.0f, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
bool ForceToWait(uint32 duration, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL); bool ForceToWait(uint32 duration, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
// QUEST RELATED // QUEST RELATED CHECK
bool SearchQuestGiverAndAcceptOrReward();
ObjectGuid ChooseNpcOrGameObjectToInteract(bool questgiverOnly = false, float distanceLimit = 0.0f); ObjectGuid ChooseNpcOrGameObjectToInteract(bool questgiverOnly = false, float distanceLimit = 0.0f);
bool HasQuestToAcceptOrReward(WorldObject* object); bool HasQuestToAcceptOrReward(WorldObject* object);
bool InteractWithNpcOrGameObjectForQuest(ObjectGuid guid); bool InteractWithNpcOrGameObjectForQuest(ObjectGuid guid);
bool AcceptQuest(Quest const* quest, ObjectGuid guid); bool CanInteractWithQuestGiver(Object* questGiver);
bool TurnInQuest(Quest const* quest, ObjectGuid guid); bool IsWithinInteractionDist(Object* object);
uint32 BestReward(Quest const* quest); uint32 BestRewardIndex(Quest const* quest);
bool IsQuestWorthDoing(Quest const* quest); bool IsQuestWorthDoing(Quest const* quest);
bool IsQuestCapableDoing(Quest const* quest); bool IsQuestCapableDoing(Quest const* quest);
// QUEST RELATED ACTION
bool SearchQuestGiverAndAcceptOrReward();
bool AcceptQuest(Quest const* quest, ObjectGuid guid);
bool TurnInQuest(Quest const* quest, ObjectGuid guid);
bool OrganizeQuestLog(); bool OrganizeQuestLog();
protected: protected: