a whole lot of bugfixes

This commit is contained in:
Nico committed 2026-09-26 10:37:37 +02:00
1 parent 0fc355fb7f
commit fec36215f6
7 files changed
+5253 -1744

No files matched your search

+79
View File
@@ -0,0 +1,79 @@
# This is the CMakeCache file.
# For build in directory: /home/wow_admin/wow_cata_server/source/TrinityCore
# It was generated by CMake: /usr/bin/cmake
# You can edit this file to change values found and used by cmake.
# If you do not want to change any of the values, simply exit the editor.
# If you do want to change a value, simply edit, save, and exit the editor.
# The syntax for the file is as follows:
# KEY:TYPE=VALUE
# KEY is the name of a variable in the cache.
# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!.
# VALUE is the current value for the KEY.
########################
# EXTERNAL cache entries
########################
//Value Computed by CMake.
CMAKE_FIND_PACKAGE_REDIRECTS_DIR:STATIC=/home/wow_admin/wow_cata_server/source/TrinityCore/CMakeFiles/pkgRedirects
//Value Computed by CMake
CMAKE_PROJECT_DESCRIPTION:STATIC=
//Value Computed by CMake
CMAKE_PROJECT_HOMEPAGE_URL:STATIC=
//Value Computed by CMake
CMAKE_PROJECT_NAME:STATIC=TrinityCore
//Path to a program.
CMAKE_UNAME:FILEPATH=/usr/bin/uname
//Value Computed by CMake
TrinityCore_BINARY_DIR:STATIC=/home/wow_admin/wow_cata_server/source/TrinityCore
//Value Computed by CMake
TrinityCore_IS_TOP_LEVEL:STATIC=ON
//Value Computed by CMake
TrinityCore_SOURCE_DIR:STATIC=/home/wow_admin/wow_cata_server/source/TrinityCore
########################
# INTERNAL cache entries
########################
//This is the directory where this CMakeCache.txt was created
CMAKE_CACHEFILE_DIR:INTERNAL=/home/wow_admin/wow_cata_server/source/TrinityCore
//Major version of cmake used to create the current loaded cache
CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3
//Minor version of cmake used to create the current loaded cache
CMAKE_CACHE_MINOR_VERSION:INTERNAL=28
//Patch version of cmake used to create the current loaded cache
CMAKE_CACHE_PATCH_VERSION:INTERNAL=3
//Path to CMake executable.
CMAKE_COMMAND:INTERNAL=/usr/bin/cmake
//Path to cpack program executable.
CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack
//Path to ctest program executable.
CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest
//Name of external makefile project generator.
CMAKE_EXTRA_GENERATOR:INTERNAL=
//Name of generator.
CMAKE_GENERATOR:INTERNAL=Unix Makefiles
//Generator instance identifier.
CMAKE_GENERATOR_INSTANCE:INTERNAL=
//Name of generator platform.
CMAKE_GENERATOR_PLATFORM:INTERNAL=
//Name of generator toolset.
CMAKE_GENERATOR_TOOLSET:INTERNAL=
//Source directory with the top level CMakeLists.txt file for this
// project
CMAKE_HOME_DIRECTORY:INTERNAL=/home/wow_admin/wow_cata_server/source/TrinityCore
//number of local generators
CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1
//Platform information initialized
CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1
//Path to CMake installation.
CMAKE_ROOT:INTERNAL=/usr/share/cmake-3.28
+1
View File
@@ -0,0 +1 @@
# This file is generated by cmake for dependency checking of the CMakeCache.txt file
@@ -21,9 +21,14 @@
// VIANO_ADVENTURERS
void AddSC_viano_adventurers();
// Viano Server diagnostics
void AddSC_vcore_diagnostics();
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
void AddCustomScripts()
{
AddSC_viano_adventurers();
AddSC_vcore_diagnostics();
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -1760,6 +1760,644 @@ private:
}
};
// WOW-PRIVATE-SERVER PATCH: Human Infestation (28138)
//
// Restores the missing capture logic for the Titanium Shackles.
// Spell 88797 used on a Hillsbrad Sentry at <= 35% health grants
// quest credit through the Captured Human Proxy and replaces the
// sentry with the matching Captured Hillsbrad Human follower.
enum HumanInfestation
{
QUEST_HUMAN_INFESTATION = 28138,
NPC_HILLSBRAD_MINER = 2269,
NPC_HILLSBRAD_SENTRY = 2270,
NPC_HILLSBRAD_FOREMAN = 2503,
NPC_CAPTURED_HUMAN_PROXY = 47697,
NPC_CAPTURED_HUMAN_MODEL_3629 = 47689,
NPC_CAPTURED_HUMAN_MODEL_3633 = 47693,
NPC_CAPTURED_HUMAN_MODEL_3632 = 47694,
NPC_CAPTURED_HUMAN_MODEL_5785 = 47695,
SPELL_TITANIUM_SHACKLES = 88797
};
struct npc_hillsbrad_captured_human : public ScriptedAI
{
npc_hillsbrad_captured_human(Creature* creature)
: ScriptedAI(creature), _checkTimer(1000) { }
void IsSummonedBy(Unit* summoner) override
{
Player* player = summoner ? summoner->ToPlayer() : nullptr;
if (!player)
{
me->DespawnOrUnsummon();
return;
}
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
me->CombatStop(true);
me->SetFaction(player->GetFaction());
// Follow slightly behind the player.
me->GetMotionMaster()->MoveFollow(player, 2.0f, float(M_PI));
}
void UpdateAI(uint32 diff) override
{
if (_checkTimer > diff)
{
_checkTimer -= diff;
return;
}
_checkTimer = 1000;
TempSummon* summon = me->ToTempSummon();
if (!summon)
{
me->DespawnOrUnsummon();
return;
}
Unit* summoner = summon->GetSummoner();
Player* player = summoner ? summoner->ToPlayer() : nullptr;
if (!player)
{
me->DespawnOrUnsummon();
return;
}
QuestStatus const status = player->GetQuestStatus(QUEST_HUMAN_INFESTATION);
// Keep followers while the quest is incomplete or complete-but-not-turned-in.
// Remove them after turn-in, abandonment, or failure.
if (status == QUEST_STATUS_NONE ||
status == QUEST_STATUS_REWARDED ||
status == QUEST_STATUS_FAILED)
{
me->DespawnOrUnsummon();
}
}
private:
uint32 _checkTimer;
};
class spell_hillsbrad_titanium_shackles : public SpellScript
{
void HandleHit()
{
Player* player = GetCaster() ? GetCaster()->ToPlayer() : nullptr;
Creature* target = GetHitCreature();
if (!player || !target)
return;
if (player->GetQuestStatus(QUEST_HUMAN_INFESTATION) != QUEST_STATUS_INCOMPLETE)
return;
if (!target->IsAlive())
return;
switch (target->GetEntry())
{
case NPC_HILLSBRAD_MINER:
case NPC_HILLSBRAD_SENTRY:
case NPC_HILLSBRAD_FOREMAN:
break;
default:
return;
}
if (target->GetHealthPct() > 35.0f)
return;
uint32 captiveEntry = 0;
// Preserve the Sentry's visual family where possible:
// 3632 <-> 5784 and 5785 <-> 5786 are the two model pairs.
switch (target->GetDisplayId())
{
case 3629:
captiveEntry = NPC_CAPTURED_HUMAN_MODEL_3629;
break;
case 3633:
captiveEntry = NPC_CAPTURED_HUMAN_MODEL_3633;
break;
case 3632:
case 5784:
captiveEntry = NPC_CAPTURED_HUMAN_MODEL_3632;
break;
case 5785:
case 5786:
captiveEntry = NPC_CAPTURED_HUMAN_MODEL_5785;
break;
default:
{
uint32 const capturedHumans[] =
{
NPC_CAPTURED_HUMAN_MODEL_3629,
NPC_CAPTURED_HUMAN_MODEL_3633,
NPC_CAPTURED_HUMAN_MODEL_3632,
NPC_CAPTURED_HUMAN_MODEL_5785
};
captiveEntry = capturedHumans[urand(0, 3)];
break;
}
}
player->KilledMonsterCredit(NPC_CAPTURED_HUMAN_PROXY);
// Player-owned summon so logout naturally cleans it up.
player->SummonCreature(
captiveEntry,
target->GetPosition(),
TEMPSUMMON_MANUAL_DESPAWN
);
target->DespawnOrUnsummon();
}
void Register() override
{
OnHit.Register(&spell_hillsbrad_titanium_shackles::HandleHit);
}
};
// WOW-PRIVATE-SERVER PATCH: Coastal Delicacies (28146)
//
// Restores the missing Hungry Mine Creeper companion and feeding sequence.
// The companion exists only in the intended Hillsbrad subzones, follows the
// quest owner, and only consumes Murlocs actually killed by that owner.
enum CoastalDelicacies
{
QUEST_COASTAL_DELICACIES = 28146,
NPC_HUNGRY_MINE_CREEPER = 47662,
NPC_MURLOC_EATEN_PROXY = 47752,
NPC_TORN_FIN_MUCKDWELLER = 2374,
NPC_TORN_FIN_COASTRUNNER = 2375,
AREA_WESTERN_STRAND = 295,
AREA_AZURELODE_MINE = 288,
POINT_COASTAL_FEED_CORPSE = 1,
COASTAL_STATE_FOLLOWING = 0,
COASTAL_STATE_MOVING_TO_CORPSE = 1,
COASTAL_STATE_EATING = 2
};
static bool IsCoastalDelicaciesArea(uint32 areaId)
{
return areaId == AREA_WESTERN_STRAND || areaId == AREA_AZURELODE_MINE;
}
static Creature* FindOwnedHungryMineCreeper(Player* player)
{
if (!player)
return nullptr;
std::list<Creature*> creepers;
GetCreatureListWithEntryInGrid(creepers, player, NPC_HUNGRY_MINE_CREEPER, 120.0f);
for (Creature* creeper : creepers)
{
if (!creeper)
continue;
TempSummon* summon = creeper->ToTempSummon();
if (!summon)
continue;
if (summon->GetSummoner() == player)
return creeper;
}
return nullptr;
}
static void DespawnOwnedHungryMineCreeper(Player* player)
{
if (Creature* creeper = FindOwnedHungryMineCreeper(player))
creeper->DespawnOrUnsummon();
}
static void EnsureHungryMineCreeper(Player* player)
{
if (!player)
return;
if (player->GetQuestStatus(QUEST_COASTAL_DELICACIES) != QUEST_STATUS_INCOMPLETE ||
!IsCoastalDelicaciesArea(player->GetAreaId()))
{
DespawnOwnedHungryMineCreeper(player);
return;
}
if (FindOwnedHungryMineCreeper(player))
return;
player->SummonCreature(
NPC_HUNGRY_MINE_CREEPER,
player->GetPosition(),
TEMPSUMMON_MANUAL_DESPAWN
);
}
struct npc_hillsbrad_hungry_mine_creeper : public ScriptedAI
{
npc_hillsbrad_hungry_mine_creeper(Creature* creature)
: ScriptedAI(creature),
_state(COASTAL_STATE_FOLLOWING),
_eatTimer(0),
_ownerCheckTimer(500) { }
void IsSummonedBy(Unit* summoner) override
{
Player* player = summoner ? summoner->ToPlayer() : nullptr;
if (!player)
{
me->DespawnOrUnsummon();
return;
}
_ownerGuid = player->GetGUID();
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
me->CombatStop(true);
me->SetFaction(player->GetFaction());
me->SetWalk(false);
FollowOwner();
}
void SetGUID(ObjectGuid const& guid, int32 id) override
{
if (id != POINT_COASTAL_FEED_CORPSE || _state != COASTAL_STATE_FOLLOWING)
return;
Creature* corpse = ObjectAccessor::GetCreature(*me, guid);
if (!IsValidFeedCorpse(corpse))
return;
_corpseGuid = guid;
_state = COASTAL_STATE_MOVING_TO_CORPSE;
me->AttackStop();
me->CombatStop(true);
me->GetMotionMaster()->MovePoint(
POINT_COASTAL_FEED_CORPSE,
corpse->GetPosition(),
false
);
}
void MovementInform(uint32 type, uint32 id) override
{
if (type != POINT_MOTION_TYPE || id != POINT_COASTAL_FEED_CORPSE)
return;
if (_state == COASTAL_STATE_MOVING_TO_CORPSE)
BeginEating();
}
void UpdateAI(uint32 diff) override
{
if (_ownerCheckTimer > diff)
_ownerCheckTimer -= diff;
else
{
_ownerCheckTimer = 500;
Player* player = GetOwnerPlayer();
if (!player ||
player->GetQuestStatus(QUEST_COASTAL_DELICACIES) != QUEST_STATUS_INCOMPLETE ||
!IsCoastalDelicaciesArea(player->GetAreaId()))
{
me->DespawnOrUnsummon();
return;
}
if (_state == COASTAL_STATE_FOLLOWING)
{
if (me->GetDistance(player) > 4.0f)
FollowOwner();
}
else if (_state == COASTAL_STATE_MOVING_TO_CORPSE)
{
Creature* corpse = GetFeedCorpse();
if (!IsValidFeedCorpse(corpse))
{
ResetToFollowing();
return;
}
if (me->GetDistance(corpse) <= 2.5f)
BeginEating();
}
}
if (_state == COASTAL_STATE_EATING)
{
if (_eatTimer > diff)
_eatTimer -= diff;
else
FinishEating();
}
}
private:
Player* GetOwnerPlayer()
{
return ObjectAccessor::GetPlayer(*me, _ownerGuid);
}
Creature* GetFeedCorpse()
{
if (_corpseGuid.IsEmpty())
return nullptr;
return ObjectAccessor::GetCreature(*me, _corpseGuid);
}
bool IsValidFeedCorpse(Creature* corpse) const
{
if (!corpse || corpse->IsAlive())
return false;
return corpse->GetEntry() == NPC_TORN_FIN_MUCKDWELLER ||
corpse->GetEntry() == NPC_TORN_FIN_COASTRUNNER;
}
void FollowOwner()
{
if (Player* player = GetOwnerPlayer())
me->GetMotionMaster()->MoveFollow(player, 2.0f, float(M_PI));
}
void BeginEating()
{
Creature* corpse = GetFeedCorpse();
if (!IsValidFeedCorpse(corpse))
{
ResetToFollowing();
return;
}
_state = COASTAL_STATE_EATING;
_eatTimer = 2000;
me->StopMoving();
me->SetFacingToObject(corpse);
// Emote 54 = one-shot special 1H attack in this client build.
// For a spider this provides a short generic feeding/attack motion.
me->HandleEmoteCommand(54);
}
void FinishEating()
{
Player* player = GetOwnerPlayer();
Creature* corpse = GetFeedCorpse();
if (!player ||
player->GetQuestStatus(QUEST_COASTAL_DELICACIES) != QUEST_STATUS_INCOMPLETE ||
!IsValidFeedCorpse(corpse))
{
ResetToFollowing();
return;
}
player->KilledMonsterCredit(NPC_MURLOC_EATEN_PROXY);
corpse->DespawnOrUnsummon();
ResetToFollowing();
}
void ResetToFollowing()
{
_corpseGuid.Clear();
_state = COASTAL_STATE_FOLLOWING;
_eatTimer = 0;
FollowOwner();
}
ObjectGuid _ownerGuid;
ObjectGuid _corpseGuid;
uint8 _state;
uint32 _eatTimer;
uint32 _ownerCheckTimer;
};
class player_hillsbrad_coastal_delicacies : public PlayerScript
{
public:
player_hillsbrad_coastal_delicacies()
: PlayerScript("player_hillsbrad_coastal_delicacies") { }
void OnQuestStatusChange(Player* player, uint32 questId) override
{
if (!player || questId != QUEST_COASTAL_DELICACIES)
return;
EnsureHungryMineCreeper(player);
}
void OnLogin(Player* player, bool /*firstLogin*/) override
{
if (player && player->GetQuestStatus(QUEST_COASTAL_DELICACIES) == QUEST_STATUS_INCOMPLETE)
EnsureHungryMineCreeper(player);
}
void OnUpdateZone(Player* player, uint32 /*newZone*/, uint32 /*newArea*/) override
{
if (player && player->GetQuestStatus(QUEST_COASTAL_DELICACIES) == QUEST_STATUS_INCOMPLETE)
EnsureHungryMineCreeper(player);
else
DespawnOwnedHungryMineCreeper(player);
}
void OnMapChanged(Player* player) override
{
if (player && player->GetQuestStatus(QUEST_COASTAL_DELICACIES) == QUEST_STATUS_INCOMPLETE)
EnsureHungryMineCreeper(player);
else
DespawnOwnedHungryMineCreeper(player);
}
void OnCreatureKill(Player* killer, Creature* killed) override
{
if (!killer || !killed)
return;
if (killer->GetQuestStatus(QUEST_COASTAL_DELICACIES) != QUEST_STATUS_INCOMPLETE ||
!IsCoastalDelicaciesArea(killer->GetAreaId()))
return;
if (killed->GetEntry() != NPC_TORN_FIN_MUCKDWELLER &&
killed->GetEntry() != NPC_TORN_FIN_COASTRUNNER)
return;
Creature* creeper = FindOwnedHungryMineCreeper(killer);
if (!creeper || !creeper->IsAIEnabled())
return;
creeper->AI()->SetGUID(killed->GetGUID(), POINT_COASTAL_FEED_CORPSE);
}
};
// WOW-PRIVATE-SERVER PATCH: Deep Mine Rescue (28156)
//
// Restores Dumass' missing rescue behavior. Quest acceptance is observed
// through PlayerScript because this TrinityCore branch does not expose a
// quest-accept hook on CreatureAI/CreatureScript.
enum DeepMineRescue
{
QUEST_DEEP_MINE_RESCUE = 28156,
NPC_DUMASS_RESCUE = 47681,
NPC_CAPTAIN_KEYTON = 47554,
SPELL_PARALYTIC_POISON = 87969
};
struct npc_hillsbrad_dumass_rescue : public ScriptedAI
{
npc_hillsbrad_dumass_rescue(Creature* creature)
: ScriptedAI(creature), _checkTimer(1000), _active(false), _finished(false) { }
void StartRescue(Player* player)
{
if (!player)
return;
_playerGuid = player->GetGUID();
_active = true;
_finished = false;
_checkTimer = 250;
me->RemoveAurasDueToSpell(SPELL_PARALYTIC_POISON);
me->SetReactState(REACT_DEFENSIVE);
me->SetWalk(false);
me->GetMotionMaster()->MoveFollow(player, 2.0f, float(M_PI));
}
void UpdateAI(uint32 diff) override
{
if (_active && !_finished)
{
if (_checkTimer > diff)
_checkTimer -= diff;
else
{
_checkTimer = 1000;
Player* player = ObjectAccessor::GetPlayer(*me, _playerGuid);
if (!player)
{
ResetRescue();
return;
}
QuestStatus const status = player->GetQuestStatus(QUEST_DEEP_MINE_RESCUE);
if (status == QUEST_STATUS_NONE ||
status == QUEST_STATUS_REWARDED ||
status == QUEST_STATUS_FAILED)
{
ResetRescue();
return;
}
if (status == QUEST_STATUS_INCOMPLETE)
{
if (Creature* keyton = me->FindNearestCreature(NPC_CAPTAIN_KEYTON, 12.0f, true))
{
_finished = true;
_active = false;
me->CombatStop(true);
me->AttackStop();
me->StopMoving();
me->SetFacingToObject(keyton);
player->GroupEventHappens(QUEST_DEEP_MINE_RESCUE, me);
// Let the original world spawn return through normal respawn handling.
me->DespawnOrUnsummon(5s);
return;
}
// Combat can interrupt following. Resume once Dumass is free again.
if (!me->IsInCombat() && me->GetDistance(player) > 4.0f)
me->GetMotionMaster()->MoveFollow(player, 2.0f, float(M_PI));
}
}
}
if (UpdateVictim())
DoMeleeAttackIfReady();
}
private:
void ResetRescue()
{
_active = false;
_finished = false;
_playerGuid.Clear();
me->CombatStop(true);
me->AttackStop();
me->GetMotionMaster()->MoveTargetedHome();
if (!me->HasAura(SPELL_PARALYTIC_POISON))
me->CastSpell(me, SPELL_PARALYTIC_POISON, true);
}
ObjectGuid _playerGuid;
uint32 _checkTimer;
bool _active;
bool _finished;
};
class player_hillsbrad_deep_mine_rescue : public PlayerScript
{
public:
player_hillsbrad_deep_mine_rescue()
: PlayerScript("player_hillsbrad_deep_mine_rescue") { }
void OnQuestStatusChange(Player* player, uint32 questId) override
{
if (!player || questId != QUEST_DEEP_MINE_RESCUE)
return;
if (player->GetQuestStatus(QUEST_DEEP_MINE_RESCUE) != QUEST_STATUS_INCOMPLETE)
return;
if (Creature* dumass = player->FindNearestCreature(NPC_DUMASS_RESCUE, 50.0f, true))
{
if (dumass->IsAIEnabled())
{
if (npc_hillsbrad_dumass_rescue* ai =
dynamic_cast<npc_hillsbrad_dumass_rescue*>(dumass->AI()))
{
ai->StartRescue(player);
}
}
}
}
};
enum GloriousHarvest
{
QUEST_GLORIOUS_HARVEST = 28114,
@@ -1810,6 +2448,12 @@ void AddSC_hillsbrad_foothills()
RegisterCreatureAI(npc_hillsbrad_welcome_steed);
RegisterCreatureAI(npc_hillsbrad_welcome_actor);
RegisterCreatureAI(npc_hillsbrad_creeper_egg);
RegisterCreatureAI(npc_hillsbrad_captured_human);
RegisterCreatureAI(npc_hillsbrad_dumass_rescue);
RegisterCreatureAI(npc_hillsbrad_hungry_mine_creeper);
new player_hillsbrad_deep_mine_rescue();
new player_hillsbrad_coastal_delicacies();
RegisterSpellScript(spell_hillsbrad_titanium_shackles);
RegisterSpellScript(spell_brazie_summon_plant);
RegisterSpellScript(spell_brazie_highlight);
RegisterSpellScript(spell_brazie_create_random_seed_sack);