Skip to content
Open
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
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ This is not a module that you need to place within that directory, but rather a
6. Add the Patch-F.MPQ to your client data directory
- **NOTE**: If you already have a Patch-F.MPQ file in use, simply change the "F" to an unused letter. I chose F as all of these changes are tied to Faction.
7. Log into MySQL and run the attached .SQL files against the acore_world database
- First, run the EntryChecker.sql file to determine if any of the id, entry, or guid are currently in use
- First, run the EntryChecker_RUN_FIRST.sql file to determine if any of the id, entry, or guid values are currently in use
- If things are found, please modify the FactionFree.sql to use values that are not in use
- After ensuring no values are already in use, or after changing to ones that are free, run the FactionFree.sql against acore_world
- Make sure your AzerothCore database is fully updated before importing the files; the SQL targets the schema shipped with the current `main` branch
8. Navigate to the directory shown under the cpp directory in this repo, copy the EXISTING PlayerUpdates.cpp file to something like PlayerUpdates.cpp.bkup
to keep the original file incase you need it in the future. Then copy the PlayerUpdates.cpp file from the repo into that location.
9. Recompile and Remake the server as normal and enjoy!
Expand Down Expand Up @@ -96,3 +97,8 @@ v1.3.5: December 12, 2024
v1.3.6: February 15, 2025
- Updated PlayerUpdates.cpp to work with current Azerothcore main branch after changes to .cpp
- Added faction 1637 to FactionFree.sql to correct faction Horde NPCs attacking Alliance players

v1.3.7: July 28, 2026
- Updated PlayerUpdates.cpp to match the current AzerothCore main branch while preserving the faction-free city behavior
- Updated creature_template inserts for the current database schema
- Made EntryChecker_RUN_FIRST.sql independent of the creature identifier column name
146 changes: 96 additions & 50 deletions cpp/src/server/game/Entities/Player/PlayerUpdates.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
Expand Down Expand Up @@ -68,14 +68,8 @@ void Player::Update(uint32 p_time)
m_nextMailDelivereTime = time_t(0);
}

// Update cinematic location, if 500ms have passed and we're doing a
// cinematic now.
_cinematicMgr->m_cinematicDiff += p_time;
if (_cinematicMgr->m_cinematicCamera && _cinematicMgr->m_activeCinematicCameraId && GetMSTimeDiffToNow(_cinematicMgr->m_lastCinematicCheck) > CINEMATIC_UPDATEDIFF)
{
_cinematicMgr->m_lastCinematicCheck = getMSTime();
_cinematicMgr->UpdateCinematicLocation(p_time);
}
// Update cinematic camera (if needed)
_cinematicMgr.UpdateCinematic(p_time);

// used to implement delayed far teleports
SetMustDelayTeleport(true);
Expand Down Expand Up @@ -204,6 +198,9 @@ void Player::Update(uint32 p_time)
// do attack
AttackerStateUpdate(victim, BASE_ATTACK);
resetAttackTimer(BASE_ATTACK);

// Blizzlike: Reset ranged swing timer when performing melee attack
resetAttackTimer(RANGED_ATTACK);
}
}

Expand All @@ -223,6 +220,9 @@ void Player::Update(uint32 p_time)
// do attack
AttackerStateUpdate(victim, OFF_ATTACK);
resetAttackTimer(OFF_ATTACK);

// Blizzlike: Reset ranged swing timer when performing melee attack
resetAttackTimer(RANGED_ATTACK);
}
}

Expand Down Expand Up @@ -332,6 +332,8 @@ void Player::Update(uint32 p_time)
}
}

UpdateAdditionalSaves(p_time);

// Handle Water/drowning
HandleDrowning(p_time);

Expand Down Expand Up @@ -396,13 +398,11 @@ void Player::Update(uint32 p_time)
// != GetCharmGUID())))
RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true);

// pussywizard:
if (m_hostileReferenceCheckTimer <= p_time)
{
m_hostileReferenceCheckTimer = 15000;
if (!GetMap()->IsDungeon())
getHostileRefMgr().deleteReferencesOutOfRange(
GetVisibilityRange());
GetCombatManager().EndCombatBeyondRange(GetVisibilityRange(), true);
}
else
m_hostileReferenceCheckTimer -= p_time;
Expand Down Expand Up @@ -701,7 +701,7 @@ void Player::UpdateRating(CombatRating cr)

void Player::UpdateAllRatings()
{
for (int cr = 0; cr < MAX_COMBAT_RATING; ++cr)
for (uint8 cr = 0; cr < MAX_COMBAT_RATING; ++cr)
UpdateRating(CombatRating(cr));
}

Expand Down Expand Up @@ -941,6 +941,11 @@ bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step)
if (!MaxValue || !SkillValue || SkillValue >= MaxValue)
return false;

// Trial account trade-skill cap (0 disables the cap)
if (uint32 trialSkillCap = sWorld->getIntConfig(CONFIG_TRIAL_TRADE_SKILL_CAP))
if (GetSession()->IsTrialAccount() && SkillValue >= trialSkillCap)
return false;

int32 Roll = irand(1, 1000);

if (Roll <= Chance)
Expand Down Expand Up @@ -1171,9 +1176,6 @@ bool Player::UpdatePosition(float x, float y, float z, float orientation,
if (GetGroup())
SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POSITION);

if (GetTrader() && !IsWithinDistInMap(GetTrader(), INTERACTION_DISTANCE))
GetSession()->SendCancelTrade(TRADE_STATUS_TRADE_CANCELED);

CheckAreaExploreAndOutdoor();

return true;
Expand Down Expand Up @@ -1235,7 +1237,8 @@ void Player::UpdateArea(uint32 newArea)
{
SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY);
pvpInfo.IsInNoPvPArea = true;
CombatStopWithPets();
if (!duel && GetCombatManager().HasPvPCombat())
CombatStopWithPets();
}
else
RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY);
Expand Down Expand Up @@ -1289,13 +1292,9 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea, bool force)
return;

if (sWorld->getBoolConfig(CONFIG_WEATHER))
{
if (Weather* weather = WeatherMgr::FindWeather(zone->ID))
weather->SendWeatherUpdateToPlayer(this);
else if (!WeatherMgr::AddWeather(zone->ID))
// send fine weather packet to remove old zone's weather
WeatherMgr::SendFineWeatherUpdateToPlayer(this);
}
GetMap()->GetOrGenerateZoneDefaultWeather(newZone);

GetMap()->SendZoneDynamicInfo(newZone, this);

sScriptMgr->OnPlayerUpdateZone(this, newZone, newArea);

Expand Down Expand Up @@ -1409,7 +1408,7 @@ void Player::UpdateHomebindTime(uint32 time)
WorldPacket data(SMSG_RAID_GROUP_ONLY, 4 + 4);
data << uint32(0);
data << uint32(0);
GetSession()->SendPacket(&data);
SendDirectMessage(&data);
}
// instance is valid, reset homebind timer
m_HomebindTimer = 0;
Expand All @@ -1432,7 +1431,7 @@ void Player::UpdateHomebindTime(uint32 time)
WorldPacket data(SMSG_RAID_GROUP_ONLY, 4 + 4);
data << uint32(m_HomebindTimer);
data << uint32(1);
GetSession()->SendPacket(&data);
SendDirectMessage(&data);
LOG_DEBUG(
"maps",
"PLAYER: Player '{}' ({}) will be teleported to homebind in 60 "
Expand All @@ -1447,6 +1446,9 @@ void Player::UpdatePvPState()

if (pvpInfo.IsHostile) // in hostile area
{
if (IsInFlight() || !m_taxi.empty()) // on taxi or taxi pending resume after login
return;

if (!IsPvP() || pvpInfo.EndTimer != 0)
UpdatePvP(true, true);
}
Expand Down Expand Up @@ -1548,6 +1550,16 @@ void Player::UpdatePvP(bool state, bool _override)
sScriptMgr->OnPlayerPVPFlagChange(this, state);
}

void Player::AtExitCombat()
{
Unit::AtExitCombat();
UpdatePotionCooldown();

if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY))
for (uint8 i = 0; i < MAX_RUNES; ++i)
SetGracePeriod(i, 0);
}

void Player::UpdatePotionCooldown(Spell* spell)
{
// no potion used i combat or still in combat
Expand Down Expand Up @@ -1598,21 +1610,12 @@ void Player::UpdateVisibilityForPlayer(bool mapChange)
// After added to map seer must be a player - there is no possibility to
// still have different seer (all charm auras must be already removed)
if (mapChange && m_seer != this)
{
m_seer = this;
}

Acore::VisibleNotifier notifierNoLarge(
*this, mapChange,
false); // visit only objects which are not large; default distance
Cell::VisitObjects(m_seer, notifierNoLarge,
GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS);
notifierNoLarge.SendToSelf();

Acore::VisibleNotifier notifierLarge(
*this, mapChange, true); // visit only large objects; maximum distance
Cell::VisitObjects(m_seer, notifierLarge, GetSightRange());
notifierLarge.SendToSelf();
Acore::VisibleNotifier notifier(*this, mapChange);
Cell::VisitObjects(GetSightPosition().GetPositionX(), GetSightPosition().GetPositionY(), GetMap(), notifier, GetSightRange());
Cell::VisitFarVisibleObjects(GetSightPosition().GetPositionX(), GetSightPosition().GetPositionY(), GetMap(), notifier, VISIBILITY_DISTANCE_GIGANTIC);
notifier.SendToSelf();

if (mapChange)
m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
Expand Down Expand Up @@ -1788,7 +1791,7 @@ void Player::UpdateTriggerVisibility()

WorldPacket packet;
udata.BuildPacket(packet);
GetSession()->SendPacket(&packet);
SendDirectMessage(&packet);
}

void Player::UpdateForQuestWorldObjects()
Expand Down Expand Up @@ -1841,7 +1844,7 @@ void Player::UpdateForQuestWorldObjects()

WorldPacket packet;
udata.BuildPacket(packet);
GetSession()->SendPacket(&packet);
SendDirectMessage(&packet);
}

void Player::UpdateTitansGrip()
Expand Down Expand Up @@ -1985,10 +1988,7 @@ void Player::UpdateCharmedAI()

Unit* target = GetVictim();
if (target)
{
SetInFront(target);
SendMovementFlagUpdate(true);
}

if (HasUnitState(UNIT_STATE_CASTING))
return;
Expand Down Expand Up @@ -2329,9 +2329,9 @@ bool Player::CanExecutePendingSpellCastRequest(SpellInfo const* spellInfo)
return true;
}

const PendingSpellCastRequest* Player::GetCastRequest(uint32 category) const
PendingSpellCastRequest const* Player::GetCastRequest(uint32 category) const
{
for (const PendingSpellCastRequest& request : SpellQueue)
for (PendingSpellCastRequest const& request : SpellQueue)
if (request.category == category)
return &request;
return nullptr;
Expand Down Expand Up @@ -2405,3 +2405,49 @@ void Player::ProcessSpellQueue()
break;
}
}

// save only the data flagged by AdditionalSavingAddMask shortly after
// important changes, so a crash loses at most a few seconds of them
void Player::UpdateAdditionalSaves(uint32 p_time)
{
if (!m_additionalSaveTimer || GetSession()->isLogingOut())
return;

if (m_additionalSaveTimer > p_time)
{
m_additionalSaveTimer -= p_time;
return;
}

uint8 mask = m_additionalSaveMask;
m_additionalSaveTimer = 0;
m_additionalSaveMask = 0;

CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();

if (mask & ADDITIONAL_SAVING_INVENTORY_AND_GOLD)
SaveInventoryAndGoldToDB(trans);

if (mask & ADDITIONAL_SAVING_QUEST_STATUS)
{
_SaveQuestStatus(trans);

// if nothing changed, nothing will happen
_SaveDailyQuestStatus(trans);
_SaveWeeklyQuestStatus(trans);
_SaveSeasonalQuestStatus(trans);
_SaveMonthlyQuestStatus(trans);
}

if (mask & ADDITIONAL_SAVING_ACHIEVEMENTS)
{
m_achievementMgr->SaveToDB(trans);

// achievements are often earned together with skill or gold changes
// (professions, riding, wealth), save those too to keep the DB consistent
_SaveSkills(trans);
SaveGoldToDB(trans);
}

CharacterDatabase.CommitTransaction(trans);
}
4 changes: 2 additions & 2 deletions sql/world/EntryChecker_RUN_FIRST.sql
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ To run this script:
/*Check to see if entry 500000 and 500001 are free to add the creature templates for the Teleport Network*/
SELECT `entry`, `name`, `subname`, `faction`, `npcflag` FROM `acore_world`.`creature_template` WHERE `entry` IN (500000, 500001);
/*Check to see if GUIDs 500000000-500000019 are free to add the creature objects for the Teleport Network*/
SELECT `guid`, `id1`, `map`, `zoneId`, `areaId` FROM `acore_world`.`creature` WHERE `guid` BETWEEN 5000000 AND 5000019;
SELECT `guid`, `map`, `zoneId`, `areaId` FROM `acore_world`.`creature` WHERE `guid` BETWEEN 5000000 AND 5000019;
/*Check to see if entry 500000, 500001, and 500003 are free to add the broadcast text entries for the Teleport Network*/
SELECT `ID`, `LanguageID`, `MaleText`, `FemaleText` FROM `acore_world`.`broadcast_text` WHERE `ID` IN (500000, 500001, 500003);
/*Check to see if entry 500000, 500001, and 500003 are free to add the npc text entries for the Teleport Network*/
Expand All @@ -29,4 +29,4 @@ SELECT `entry`, `type`, `displayId`, `name` FROM `acore_world`.`gameobject_templ
SELECT `guid`, `id`, `map`, `zoneId`, `areaId` FROM `acore_world`.`gameobject` WHERE `guid` BETWEEN 5000000 AND 5000049;

/*AGAIN: Please note that if you have any results back from these queries you will need to modify the FactionFree.sql
to use new and free entry, id, or GUID values.*/
to use new and free entry, id, or GUID values.*/
Loading