Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/common/Collision/Maps/MapDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ struct MmapTileHeader
// All padding fields must be handled and initialized to ensure mmaps_generator will produce binary-identical *.mmtile files
static_assert(sizeof(MmapTileHeader) == 20, "MmapTileHeader size is not correct, adjust the padding field size");
static_assert(sizeof(MmapTileHeader) == (sizeof(MmapTileHeader::mmapMagic) +
sizeof(MmapTileHeader::dtVersion) +
sizeof(MmapTileHeader::mmapVersion) +
sizeof(MmapTileHeader::size) +
sizeof(MmapTileHeader::usesLiquids) +
sizeof(MmapTileHeader::padding)), "MmapTileHeader has uninitialized padding fields");
sizeof(MmapTileHeader::dtVersion) +
sizeof(MmapTileHeader::mmapVersion) +
sizeof(MmapTileHeader::size) +
sizeof(MmapTileHeader::usesLiquids) +
sizeof(MmapTileHeader::padding)), "MmapTileHeader has uninitialized padding fields");

enum NavArea
{
Expand Down
1 change: 1 addition & 0 deletions src/server/game/AI/ScriptedAI/ScriptedGossip.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ enum eTradeskill
TRADESKILL_SKINNING = 13,
TRADESKILL_JEWLCRAFTING = 14,
TRADESKILL_INSCRIPTION = 15,
TRADESKILL_LINGUISTICS = 16,

TRADESKILL_LEVEL_NONE = 0,
TRADESKILL_LEVEL_APPRENTICE = 1,
Expand Down
90 changes: 88 additions & 2 deletions src/server/game/Entities/Creature/Creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(), m_grou
m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_cannotReachTarget(false), m_cannotReachTimer(0),
m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_homePosition(), m_transportHomePosition(),
m_creatureInfo(nullptr), m_creatureData(nullptr), m_stringIds(), _waypointPathId(0), _currentWaypointNodeInfo(0, 0),
m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(false), _lastDamagedTime(0),
m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(false), m_assistCheckTime(0), _lastDamagedTime(0),
_regenerateHealth(true), _regenerateHealthLock(false), _isMissingCanSwimFlagOutOfCombat(false)
{
m_regenTimer = CREATURE_REGEN_INTERVAL;
Expand Down Expand Up @@ -804,6 +804,34 @@ void Creature::Update(uint32 diff)
m_boundaryCheckTime -= diff;
}

if (IsEngaged() && IsAlive() && !IsPet() && !IsCharmed() && !IsTotem() && !IsTrigger())
{
// Only check for creatures that can actually call for help
if (!GetCharmerOrOwnerGUID().IsPlayer())
{
if (diff >= m_assistCheckTime)
{
float radius = sWorld->getFloatConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS);
if (radius > 0.0f)
{
// Use CallForHelp which directly engages nearby creatures
CallForHelp(radius);
}

// Set next assistance check time
m_assistCheckTime = sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY);
}
else
m_assistCheckTime -= diff;
}
}
else
{
// Reset timer when not in combat
if (m_assistCheckTime > 0)
m_assistCheckTime = 0;
}

// if periodic combat pulse is enabled and we are both in combat and in a dungeon, do this now
if (m_combatPulseDelay > 0 && IsEngaged() && GetMap()->IsDungeon())
{
Expand Down Expand Up @@ -2330,6 +2358,7 @@ void Creature::CallAssistance()

float radius = sWorld->getFloatConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS);


if (radius > 0)
{
std::list<Creature*> assistList;
Expand Down Expand Up @@ -2420,8 +2449,49 @@ bool Creature::CanAssistTo(Unit const* u, Unit const* enemy, bool checkfaction /
}

// skip non hostile to caster enemy creatures
// Modified: Allow assistance against enemies who are either hostile OR have attacked faction members
// This allows NPCs to defend against neutral players who initiate combat
if (!IsHostileTo(enemy))
return false;
{
// If enemy is a player and has recently damaged faction members, allow assistance
if (enemy->GetTypeId() == TYPEID_PLAYER)
{
// Check if the player is in combat with faction members
if (!enemy->IsInCombat())
return false;

// Additional check: ensure the enemy has actually attacked our faction
bool hasAttackedFaction = false;
if (Unit* victim = enemy->GetVictim())
{
if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->GetFaction() == GetFaction())
hasAttackedFaction = true;
}

// Also check combat manager for any faction targets
if (!hasAttackedFaction)
{
std::vector<Unit*> combatTargets;
for (auto const& pair : enemy->GetCombatManager().GetPvECombatRefs())
{
if (Unit* target = pair.second->GetOther(enemy))
{
if (target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->GetFaction() == GetFaction())
{
hasAttackedFaction = true;
break;
}
}
}
}

if (!hasAttackedFaction)
return false;
}
else
// For non-player enemies, keep the original hostile check
return false;
}

return true;
}
Expand Down Expand Up @@ -3266,6 +3336,19 @@ void Creature::AtEngage(Unit* target)
}
}

// Initialize assistance check timer to trigger first check after 5 seconds
if (!IsPet() && !IsCharmed() && !GetCharmerOrOwnerGUID().IsPlayer() && !IsTotem() && !IsTrigger())
{
m_assistCheckTime = sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY);
}

// Call for assistance from nearby creatures
// Only do this for non-player controlled creatures in normal world content
if (!IsPet() && !IsCharmed() && !GetCharmerOrOwnerGUID().IsPlayer() && !IsTotem() && !IsTrigger())
{
CallAssistance();
}

if (CreatureAI* ai = AI())
ai->JustEngagedWith(target);
if (CreatureGroup* formation = GetFormation())
Expand All @@ -3280,6 +3363,9 @@ void Creature::AtDisengage()
if (IsAlive() && HasDynamicFlag(UNIT_DYNFLAG_TAPPED))
ReplaceAllDynamicFlags(GetCreatureTemplate()->dynamicflags);

// Reset assistance timer when leaving combat
m_assistCheckTime = 0;

if (IsPet() || IsGuardian()) // update pets' speed for catchup OOC speed
{
UpdateSpeed(MOVE_RUN);
Expand Down
1 change: 1 addition & 0 deletions src/server/game/Entities/Creature/Creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
// Regenerate health
bool _regenerateHealth; // Set on creation
bool _regenerateHealthLock; // Dynamically set
uint32 m_assistCheckTime;

bool _isMissingCanSwimFlagOutOfCombat;
};
Expand Down
3 changes: 2 additions & 1 deletion src/server/game/Entities/Item/ItemTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,8 @@ enum ItemSubclassRecipe
ITEM_SUBCLASS_ENCHANTING_FORMULA = 8,
ITEM_SUBCLASS_FISHING_MANUAL = 9,
ITEM_SUBCLASS_JEWELCRAFTING_RECIPE = 10,
ITEM_SUBCLASS_INSCRIPTION_TECHNIQUE = 11
ITEM_SUBCLASS_INSCRIPTION_TECHNIQUE = 11,
ITEM_SUBCLASS_LINGUISTICS_BOOK = 12
};

#define MAX_ITEM_SUBCLASS_RECIPE 12
Expand Down
3 changes: 2 additions & 1 deletion src/server/game/Quests/QuestDef.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ enum QuestTradeSkill
QUEST_TRSKILL_MINING = 11,
QUEST_TRSKILL_FISHING = 12,
QUEST_TRSKILL_SKINNING = 13,
QUEST_TRSKILL_JEWELCRAFTING = 14
QUEST_TRSKILL_JEWELCRAFTING = 14,
QUEST_TRSKILL_LINGUISTICS = 15
};

enum QuestStatus : uint8
Expand Down
2 changes: 1 addition & 1 deletion src/server/game/Spells/SpellMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@ bool IsPrimaryProfessionSkill(uint32 skill);

inline bool IsProfessionSkill(uint32 skill)
{
return IsPrimaryProfessionSkill(skill) || skill == SKILL_FISHING || skill == SKILL_COOKING || skill == SKILL_FIRST_AID;
return IsPrimaryProfessionSkill(skill) || skill == SKILL_FISHING || skill == SKILL_COOKING || skill == SKILL_FIRST_AID || skill == SKILL_LINGUISTICS;
}

inline bool IsProfessionOrRidingSkill(uint32 skill)
Expand Down
18 changes: 15 additions & 3 deletions src/server/shared/SharedDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -1327,7 +1327,16 @@ enum SpellCustomErrors
SPELL_CUSTOM_ERROR_MAX_NUMBER_OF_RECRUITS = 96, // You already have the max number of recruits.
SPELL_CUSTOM_ERROR_MAX_NUMBER_OF_VOLUNTEERS = 97, // You already have the max number of volunteers.
SPELL_CUSTOM_ERROR_FROSTMOURNE_RENDERED_RESURRECT = 98, // Frostmourne has rendered you unable to resurrect.
SPELL_CUSTOM_ERROR_CANT_MOUNT_WITH_SHAPESHIFT = 99 // You can't mount while affected by that shapeshift.
SPELL_CUSTOM_ERROR_CANT_MOUNT_WITH_SHAPESHIFT = 99, // You can't mount while affected by that shapeshift.
SPELL_CUSTOM_ERROR_INTRO_QUEST_ACTIVE = 100,// You cannot use that until you've completed the introduction quest.
SPELL_CUSTOM_ERROR_STORMWIND_NEUTRAL = 101,// You must be at least Neutral with Stormwind to use that.
SPELL_CUSTOM_ERROR_IRONFORGEORGNOME_NEUTRAL = 102,// You must be at least Neutral with Ironforge or Gnomeregan Exiles to use that.
SPELL_CUSTOM_ERROR_DARNASSUS_NEUTRAL = 103,// You must be at least Neutral with Darnassus to use that.
SPELL_CUSTOM_ERROR_EXODAR_NEUTRAL = 104,// You must be at least Neutral with Exodar to use that.
SPELL_CUSTOM_ERROR_ORGRIMMARORDARKSPEAR_NEUTRAL = 105,// You must be at least Neutral with Orgrimmar or Darkspear Trolls to use that.
SPELL_CUSTOM_ERROR_THUNDERBLUFF_NEUTRAL = 106,// You must be at least Neutral with Thunder Bluff to use that.
SPELL_CUSTOM_ERROR_UNDERCITY_NEUTRAL = 107,// You must be at least Neutral with Undercity to use that.
SPELL_CUSTOM_ERROR_SILVERMOONCITY_NEUTRAL = 108 // You must be at least Neutral with Silvermoon City to use that.
};

enum StealthType
Expand Down Expand Up @@ -2925,7 +2934,8 @@ enum QuestSort
QUEST_SORT_JEWELCRAFTING = 373,
QUEST_SORT_NOBLEGARDEN = 374,
QUEST_SORT_PILGRIMS_BOUNTY = 375,
QUEST_SORT_LOVE_IS_IN_THE_AIR = 376
QUEST_SORT_LOVE_IS_IN_THE_AIR = 376,
QUEST_SORT_LINGUISTICS = 377
};

constexpr uint8 ClassByQuestSort(int32 QuestSort)
Expand Down Expand Up @@ -3099,7 +3109,8 @@ enum SkillType
SKILL_PET_WASP = 785,
SKILL_PET_EXOTIC_RHINO = 786,
SKILL_PET_EXOTIC_CORE_HOUND = 787,
SKILL_PET_EXOTIC_SPIRIT_BEAST = 788
SKILL_PET_EXOTIC_SPIRIT_BEAST = 788,
SKILL_LINGUISTICS = 789
};

#define MAX_SKILL_TYPE 789
Expand Down Expand Up @@ -3133,6 +3144,7 @@ constexpr uint32 SkillByQuestSort(int32 QuestSort)
case QUEST_SORT_FIRST_AID: return SKILL_FIRST_AID;
case QUEST_SORT_JEWELCRAFTING: return SKILL_JEWELCRAFTING;
case QUEST_SORT_INSCRIPTION: return SKILL_INSCRIPTION;
case QUEST_SORT_LINGUISTICS: return SKILL_LINGUISTICS;
}
return 0;
}
Expand Down