Skip to content

Commit

Permalink
Core/Creatures: Implemented serverside checks for UNIT_FLAG2_INTERACT…
Browse files Browse the repository at this point in the history
…_WHILE_HOSTILE and UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT

* Also stop sending npc flags for hostile creatures
  • Loading branch information
Shauren committed Mar 2, 2024
1 parent 97d7ccd commit c2e36de
Show file tree
Hide file tree
Showing 12 changed files with 116 additions and 35 deletions.
30 changes: 30 additions & 0 deletions src/server/game/Entities/Creature/Creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/)

// TODO: migrate these in DB
_staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_2_ALLOW_MOUNTED_COMBAT, (GetCreatureDifficulty()->TypeFlags & CREATURE_TYPE_FLAG_ALLOW_MOUNTED_COMBAT) != 0);
SetInteractionAllowedInCombat((GetCreatureDifficulty()->TypeFlags & CREATURE_TYPE_FLAG_ALLOW_INTERACTION_WHILE_IN_COMBAT) != 0);
SetTreatAsRaidUnit((GetCreatureDifficulty()->TypeFlags & CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT) != 0);

return true;
Expand Down Expand Up @@ -2985,6 +2986,35 @@ void Creature::AllLootRemovedFromCorpse()
m_respawnTime = std::max<time_t>(m_corpseRemoveTime + m_respawnDelay, m_respawnTime);
}

void Creature::SetInteractionAllowedWhileHostile(bool interactionAllowed)
{
_staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_5_INTERACT_WHILE_HOSTILE, interactionAllowed);
Unit::SetInteractionAllowedWhileHostile(interactionAllowed);
}

void Creature::SetInteractionAllowedInCombat(bool interactionAllowed)
{
_staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_3_ALLOW_INTERACTION_WHILE_IN_COMBAT, interactionAllowed);
Unit::SetInteractionAllowedInCombat(interactionAllowed);
}

void Creature::UpdateNearbyPlayersInteractions()
{
Unit::UpdateNearbyPlayersInteractions();

// If as a result of npcflag updates we stop seeing UNIT_NPC_FLAG_QUESTGIVER then
// we must also send SMSG_QUEST_GIVER_STATUS_MULTIPLE because client will not request it automatically
if (IsQuestGiver())
{
auto sender = [&](Player const* receiver)
{
receiver->PlayerTalkClass->SendQuestGiverStatus(receiver->GetQuestDialogStatus(this), GetGUID());
};
Trinity::MessageDistDeliverer notifier(this, sender, GetVisibilityRange());
Cell::VisitWorldObjects(this, notifier, GetVisibilityRange());
}
}

bool Creature::HasScalableLevels() const
{
return m_unitData->ContentTuningID != 0;
Expand Down
4 changes: 4 additions & 0 deletions src/server/game/Entities/Creature/Creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
bool IsElite() const;
bool isWorldBoss() const;

void SetInteractionAllowedWhileHostile(bool interactionAllowed) override;
void SetInteractionAllowedInCombat(bool interactionAllowed) override;
void UpdateNearbyPlayersInteractions() override;

bool HasScalableLevels() const;
void ApplyLevelScaling();
uint8 GetLevelForTarget(WorldObject const* target) const override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ TC_API_EXPORT EnumText EnumUtils<CreatureFlagsExtra>::ToString(CreatureFlagsExtr
case CREATURE_FLAG_EXTRA_NO_XP: return { "CREATURE_FLAG_EXTRA_NO_XP", "CREATURE_FLAG_EXTRA_NO_XP", "creature kill does not provide XP" };
case CREATURE_FLAG_EXTRA_TRIGGER: return { "CREATURE_FLAG_EXTRA_TRIGGER", "CREATURE_FLAG_EXTRA_TRIGGER", "trigger creature" };
case CREATURE_FLAG_EXTRA_NO_TAUNT: return { "CREATURE_FLAG_EXTRA_NO_TAUNT", "CREATURE_FLAG_EXTRA_NO_TAUNT", "creature is immune to taunt auras and 'attack me' effects" };
case CREATURE_FLAG_EXTRA_UNUSED_9: return { "CREATURE_FLAG_EXTRA_UNUSED_9", "CREATURE_FLAG_EXTRA_UNUSED_9", "creature won't update movement flags" };
case CREATURE_FLAG_EXTRA_UNUSED_9: return { "CREATURE_FLAG_EXTRA_UNUSED_9", "CREATURE_FLAG_EXTRA_UNUSED_9", "" };
case CREATURE_FLAG_EXTRA_GHOST_VISIBILITY: return { "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "creature will only be visible to dead players" };
case CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK: return { "CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK", "CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK", "creature will use offhand attacks" };
case CREATURE_FLAG_EXTRA_NO_SELL_VENDOR: return { "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "players can't sell items to this vendor" };
Expand Down
18 changes: 12 additions & 6 deletions src/server/game/Entities/Object/Updates/ViewerDependentValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,15 +326,21 @@ class ViewerDependentValue<UF::UnitData::NpcFlagsTag>
static value_type GetValue(UF::UnitData const* unitData, uint32 i, Unit const* unit, Player const* receiver)
{
value_type npcFlag = unitData->NpcFlags[i];
if (i == 0)
if (npcFlag)
{
if (Creature const* creature = unit->ToCreature())
if ((!unit->IsInteractionAllowedInCombat() && unit->IsInCombat())
|| (!unit->IsInteractionAllowedWhileHostile() && unit->IsHostileTo(receiver)))
npcFlag = 0;
else if (Creature const* creature = unit->ToCreature())
{
if (!receiver->CanSeeGossipOn(creature))
npcFlag &= ~(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
if (i == 0)
{
if (!receiver->CanSeeGossipOn(creature))
npcFlag &= ~(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);

if (!receiver->CanSeeSpellClickOn(creature))
npcFlag &= ~UNIT_NPC_FLAG_SPELLCLICK;
if (!receiver->CanSeeSpellClickOn(creature))
npcFlag &= ~UNIT_NPC_FLAG_SPELLCLICK;
}
}
}
return npcFlag;
Expand Down
14 changes: 12 additions & 2 deletions src/server/game/Entities/Player/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1986,7 +1986,10 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid const& guid, NPCFlags npcFl
return nullptr;

// not unfriendly/hostile
if (!creature->HasUnitFlag2(UNIT_FLAG2_INTERACT_WHILE_HOSTILE) && creature->GetReactionTo(this) <= REP_UNFRIENDLY)
if (!creature->IsInteractionAllowedWhileHostile() && creature->GetReactionTo(this) <= REP_UNFRIENDLY)
return nullptr;

if (creature->IsInCombat() && !creature->IsInteractionAllowedInCombat())
return nullptr;

// not too far, taken from CGGameUI::SetInteractTarget
Expand Down Expand Up @@ -16188,6 +16191,13 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object const* questgiver) const
}
case TYPEID_UNIT:
{
Creature const* questGiverCreature = questgiver->ToCreature();
if (!questGiverCreature->IsInteractionAllowedWhileHostile() && questGiverCreature->IsHostileTo(this))
return QuestGiverStatus::None;

if (!questGiverCreature->IsInteractionAllowedInCombat() && questGiverCreature->IsInCombat())
return QuestGiverStatus::None;

if (CreatureAI* ai = questgiver->ToCreature()->AI())
if (Optional<QuestGiverStatus> questStatus = ai->GetDialogStatus(this))
return *questStatus;
Expand Down Expand Up @@ -17341,7 +17351,7 @@ void Player::SendQuestGiverStatusMultiple(GuidUnorderedSet const& guids)
{
// need also pet quests case support
Creature* questgiver = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, *itr);
if (!questgiver || questgiver->IsHostileTo(this))
if (!questgiver)
continue;
if (!questgiver->HasNpcFlag(UNIT_NPC_FLAG_QUESTGIVER))
continue;
Expand Down
34 changes: 34 additions & 0 deletions src/server/game/Entities/Unit/Unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8648,6 +8648,9 @@ void Unit::AtEnterCombat()

RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::EnteringCombat);
Unit::ProcSkillsAndAuras(this, nullptr, PROC_FLAG_ENTER_COMBAT, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);

if (!IsInteractionAllowedInCombat())
UpdateNearbyPlayersInteractions();
}

void Unit::AtExitCombat()
Expand All @@ -8661,6 +8664,9 @@ void Unit::AtExitCombat()
}

RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::LeavingCombat);

if (!IsInteractionAllowedInCombat())
UpdateNearbyPlayersInteractions();
}

void Unit::AtTargetAttacked(Unit* target, bool canInitialAggro)
Expand Down Expand Up @@ -8699,6 +8705,34 @@ void Unit::UpdatePetCombatState()
RemoveUnitFlag(UNIT_FLAG_PET_IN_COMBAT);
}

void Unit::SetInteractionAllowedWhileHostile(bool interactionAllowed)
{
if (interactionAllowed)
SetUnitFlag2(UNIT_FLAG2_INTERACT_WHILE_HOSTILE);
else
RemoveUnitFlag2(UNIT_FLAG2_INTERACT_WHILE_HOSTILE);

UpdateNearbyPlayersInteractions();
}

void Unit::SetInteractionAllowedInCombat(bool interactionAllowed)
{
if (interactionAllowed)
SetUnitFlag3(UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT);
else
RemoveUnitFlag3(UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT);

if (IsInCombat())
UpdateNearbyPlayersInteractions();
}

void Unit::UpdateNearbyPlayersInteractions()
{
for (uint32 i = 0; i < m_unitData->NpcFlags.size(); ++i)
if (m_unitData->NpcFlags[i])
ForceUpdateFieldChange(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::NpcFlags, i));
}

//======================================================================

DiminishingLevels Unit::GetDiminishing(DiminishingGroup group) const
Expand Down
9 changes: 9 additions & 0 deletions src/server/game/Entities/Unit/Unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -1040,6 +1040,15 @@ class TC_GAME_API Unit : public WorldObject
void SetInCombatWith(Unit* enemy, bool addSecondUnitSuppressed = false) { if (enemy) m_combatManager.SetInCombatWith(enemy, addSecondUnitSuppressed); }
void ClearInCombat() { m_combatManager.EndAllCombat(); }
void UpdatePetCombatState();

bool IsInteractionAllowedWhileHostile() const { return HasUnitFlag2(UNIT_FLAG2_INTERACT_WHILE_HOSTILE); }
virtual void SetInteractionAllowedWhileHostile(bool interactionAllowed);

bool IsInteractionAllowedInCombat() const { return HasUnitFlag3(UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT); }
virtual void SetInteractionAllowedInCombat(bool interactionAllowed);

virtual void UpdateNearbyPlayersInteractions();

// Threat handling
bool IsThreatened() const;
bool IsThreatenedBy(Unit const* who) const { return who && m_threatManager.IsThreatenedBy(who, true); }
Expand Down
4 changes: 2 additions & 2 deletions src/server/game/Entities/Unit/UnitDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ enum UnitFlags3 : uint32
UNIT_FLAG3_ALREADY_SKINNED = 0x00020000,
UNIT_FLAG3_SUPPRESS_ALL_NPC_SOUNDS = 0x00040000, // TITLE Suppress all NPC sounds DESCRIPTION Skips playing sounds on beginning and end of npc interaction for all npcs as long as npc with this flag is visible
UNIT_FLAG3_SUPPRESS_NPC_SOUNDS = 0x00080000, // TITLE Suppress NPC sounds DESCRIPTION Skips playing sounds on beginning and end of npc interaction
UNIT_FLAG3_UNK20 = 0x00100000,
UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT = 0x00100000, // TITLE Allow Interaction While in Combat DESCRIPTION Allows using various NPC functions while in combat (vendor, gossip, questgiver)
UNIT_FLAG3_UNK21 = 0x00200000,
UNIT_FLAG3_DONT_FADE_OUT = 0x00400000,
UNIT_FLAG3_UNK23 = 0x00800000,
Expand All @@ -281,7 +281,7 @@ enum UnitFlags3 : uint32
UNIT_FLAG3_IGNORE_COMBAT | UNIT_FLAG3_SUPPRESS_NPC_FEEDBACK | UNIT_FLAG3_UNK10 | UNIT_FLAG3_UNK11 |
UNIT_FLAG3_UNK12 | /* UNIT_FLAG3_FAKE_DEAD | */ /* UNIT_FLAG3_NO_FACING_ON_INTERACT_AND_FAST_FACING_CHASE | */ /* UNIT_FLAG3_UNTARGETABLE_FROM_UI | */
/* UNIT_FLAG3_NO_FACING_ON_INTERACT_WHILE_FAKE_DEAD | */ UNIT_FLAG3_ALREADY_SKINNED | /* UNIT_FLAG3_SUPPRESS_ALL_NPC_SOUNDS | */ /* UNIT_FLAG3_SUPPRESS_NPC_SOUNDS | */
UNIT_FLAG3_UNK20 | UNIT_FLAG3_UNK21 | /* UNIT_FLAG3_DONT_FADE_OUT | */ UNIT_FLAG3_UNK23 |
UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT | UNIT_FLAG3_UNK21 | /* UNIT_FLAG3_DONT_FADE_OUT | */ UNIT_FLAG3_UNK23 |
/* UNIT_FLAG3_FORCE_HIDE_NAMEPLATE | */ UNIT_FLAG3_UNK25 | UNIT_FLAG3_UNK26 | UNIT_FLAG3_UNK27 |
UNIT_FLAG3_UNK28 | UNIT_FLAG3_UNK29 | UNIT_FLAG3_UNK30 | UNIT_FLAG3_UNK31), // SKIP
UNIT_FLAG3_ALLOWED = (0xFFFFFFFF & ~UNIT_FLAG3_DISALLOWED) // SKIP
Expand Down
6 changes: 3 additions & 3 deletions src/server/game/Entities/Unit/enuminfo_UnitDefines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ TC_API_EXPORT EnumText EnumUtils<UnitFlags3>::ToString(UnitFlags3 value)
case UNIT_FLAG3_ALREADY_SKINNED: return { "UNIT_FLAG3_ALREADY_SKINNED", "UNIT_FLAG3_ALREADY_SKINNED", "" };
case UNIT_FLAG3_SUPPRESS_ALL_NPC_SOUNDS: return { "UNIT_FLAG3_SUPPRESS_ALL_NPC_SOUNDS", "Suppress all NPC sounds", "Skips playing sounds on beginning and end of npc interaction for all npcs as long as npc with this flag is visible" };
case UNIT_FLAG3_SUPPRESS_NPC_SOUNDS: return { "UNIT_FLAG3_SUPPRESS_NPC_SOUNDS", "Suppress NPC sounds", "Skips playing sounds on beginning and end of npc interaction" };
case UNIT_FLAG3_UNK20: return { "UNIT_FLAG3_UNK20", "UNIT_FLAG3_UNK20", "" };
case UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT: return { "UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT", "Allow Interaction While in Combat", "Allows using various NPC functions while in combat (vendor, gossip, questgiver)" };
case UNIT_FLAG3_UNK21: return { "UNIT_FLAG3_UNK21", "UNIT_FLAG3_UNK21", "" };
case UNIT_FLAG3_DONT_FADE_OUT: return { "UNIT_FLAG3_DONT_FADE_OUT", "UNIT_FLAG3_DONT_FADE_OUT", "" };
case UNIT_FLAG3_UNK23: return { "UNIT_FLAG3_UNK23", "UNIT_FLAG3_UNK23", "" };
Expand Down Expand Up @@ -353,7 +353,7 @@ TC_API_EXPORT UnitFlags3 EnumUtils<UnitFlags3>::FromIndex(size_t index)
case 17: return UNIT_FLAG3_ALREADY_SKINNED;
case 18: return UNIT_FLAG3_SUPPRESS_ALL_NPC_SOUNDS;
case 19: return UNIT_FLAG3_SUPPRESS_NPC_SOUNDS;
case 20: return UNIT_FLAG3_UNK20;
case 20: return UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT;
case 21: return UNIT_FLAG3_UNK21;
case 22: return UNIT_FLAG3_DONT_FADE_OUT;
case 23: return UNIT_FLAG3_UNK23;
Expand Down Expand Up @@ -394,7 +394,7 @@ TC_API_EXPORT size_t EnumUtils<UnitFlags3>::ToIndex(UnitFlags3 value)
case UNIT_FLAG3_ALREADY_SKINNED: return 17;
case UNIT_FLAG3_SUPPRESS_ALL_NPC_SOUNDS: return 18;
case UNIT_FLAG3_SUPPRESS_NPC_SOUNDS: return 19;
case UNIT_FLAG3_UNK20: return 20;
case UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT: return 20;
case UNIT_FLAG3_UNK21: return 21;
case UNIT_FLAG3_DONT_FADE_OUT: return 22;
case UNIT_FLAG3_UNK23: return 23;
Expand Down
7 changes: 7 additions & 0 deletions src/server/game/Globals/ObjectMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1646,10 +1646,17 @@ void ObjectMgr::ChooseCreatureFlags(CreatureTemplate const* cInfo, uint64* npcFl
*unitFlags2 = ChooseCreatureFlagSource(unit_flags2);
if (staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_CANNOT_TURN))
*unitFlags2 |= UNIT_FLAG2_CANNOT_TURN;

if (staticFlags.HasFlag(CREATURE_STATIC_FLAG_5_INTERACT_WHILE_HOSTILE))
*unitFlags2 |= UNIT_FLAG2_INTERACT_WHILE_HOSTILE;
}

if (unitFlags3)
{
*unitFlags3 = ChooseCreatureFlagSource(unit_flags3);
if (staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_ALLOW_INTERACTION_WHILE_IN_COMBAT))
*unitFlags3 |= UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT;
}

#undef ChooseCreatureFlagSource
}
Expand Down
21 changes: 1 addition & 20 deletions src/server/game/Handlers/QuestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@

void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPackets::Quest::QuestGiverStatusQuery& packet)
{
QuestGiverStatus questStatus = QuestGiverStatus::None;

Object* questGiver = ObjectAccessor::GetObjectByTypeMask(*_player, packet.QuestGiverGUID, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT);
if (!questGiver)
Expand All @@ -49,25 +48,7 @@ void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPackets::Quest::QuestG
return;
}

switch (questGiver->GetTypeId())
{
case TYPEID_UNIT:
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for npc {}", questGiver->GetGUID().ToString());
if (!questGiver->ToCreature()->IsHostileTo(_player)) // do not show quest status to enemies
questStatus = _player->GetQuestDialogStatus(questGiver);
break;
}
case TYPEID_GAMEOBJECT:
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for GameObject {}", questGiver->GetGUID().ToString());
questStatus = _player->GetQuestDialogStatus(questGiver);
break;
}
default:
TC_LOG_ERROR("network", "QuestGiver called for unexpected type {}", questGiver->GetTypeId());
break;
}
QuestGiverStatus questStatus = _player->GetQuestDialogStatus(questGiver);

//inform client about status of quest
_player->PlayerTalkClass->SendQuestGiverStatus(questStatus, packet.QuestGiverGUID);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ struct boss_sister_svalna : public BossAI
CastSpellExtraArgs args;
args.AddSpellBP0(1);
summon->CastSpell(target, VEHICLE_SPELL_RIDE_HARDCODED, args);
summon->SetUnitFlag2(UNIT_FLAG2_INTERACT_WHILE_HOSTILE);
summon->SetInteractionAllowedWhileHostile(true);
}
break;
default:
Expand Down

0 comments on commit c2e36de

Please sign in to comment.