режим предателя
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
local AIO = AIO or require("AIO")
|
||||
|
||||
local ADDON_NAME = "MoonWellClient"
|
||||
local HANDLER_NAME = "Init"
|
||||
local GAME_MODE_NORMAL = 0
|
||||
local GAME_MODE_TRAITOR = 1
|
||||
local PLAYER_EVENT_ON_LOGIN = 3
|
||||
local AIO_INIT_SEND_DELAY_MS = 1000
|
||||
|
||||
local MoonWellAIO = rawget(_G, "MoonWellAIO") or {}
|
||||
_G.MoonWellAIO = MoonWellAIO
|
||||
local PendingSyncEvents = {}
|
||||
|
||||
local function GetPlayerGameMode(player)
|
||||
if not player then
|
||||
return GAME_MODE_NORMAL
|
||||
end
|
||||
|
||||
local query = CharDBQuery(
|
||||
"SELECT game_mode FROM mod_gamemodes_characters WHERE guid = " .. player:GetGUIDLow() .. " LIMIT 1"
|
||||
)
|
||||
|
||||
if not query or query:IsNull(0) then
|
||||
return GAME_MODE_NORMAL
|
||||
end
|
||||
|
||||
local gameMode = query:GetUInt8(0)
|
||||
if gameMode == GAME_MODE_TRAITOR then
|
||||
return GAME_MODE_TRAITOR
|
||||
end
|
||||
|
||||
return GAME_MODE_NORMAL
|
||||
end
|
||||
|
||||
function MoonWellAIO.GetPlayerGameMode(player)
|
||||
return GetPlayerGameMode(player)
|
||||
end
|
||||
|
||||
function MoonWellAIO.SendPlayerGameMode(player)
|
||||
if not player then
|
||||
return GAME_MODE_NORMAL
|
||||
end
|
||||
|
||||
local gameMode = GetPlayerGameMode(player)
|
||||
AIO.Handle(player, ADDON_NAME, HANDLER_NAME, gameMode)
|
||||
return gameMode
|
||||
end
|
||||
|
||||
local function CancelPendingSync(playerGuidLow)
|
||||
local eventId = PendingSyncEvents[playerGuidLow]
|
||||
if eventId then
|
||||
RemoveEventById(eventId)
|
||||
PendingSyncEvents[playerGuidLow] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function MoonWellAIO.SchedulePlayerGameMode(player, delayMs)
|
||||
if not player then
|
||||
return
|
||||
end
|
||||
|
||||
local playerGuidLow = player:GetGUIDLow()
|
||||
local playerGuid = player:GetGUID()
|
||||
|
||||
CancelPendingSync(playerGuidLow)
|
||||
|
||||
PendingSyncEvents[playerGuidLow] = CreateLuaEvent(function()
|
||||
PendingSyncEvents[playerGuidLow] = nil
|
||||
|
||||
local onlinePlayer = GetPlayerByGUID(playerGuid)
|
||||
if onlinePlayer then
|
||||
MoonWellAIO.SendPlayerGameMode(onlinePlayer)
|
||||
end
|
||||
end, delayMs or AIO_INIT_SEND_DELAY_MS, 1)
|
||||
end
|
||||
|
||||
-- Do not append MoonWellClient blocks directly into the AIO init packet:
|
||||
-- the client addon may register its handlers slightly later than AIO itself.
|
||||
AIO.AddOnInit(function(msg, player)
|
||||
MoonWellAIO.SchedulePlayerGameMode(player, AIO_INIT_SEND_DELAY_MS)
|
||||
return msg
|
||||
end)
|
||||
|
||||
RegisterPlayerEvent(PLAYER_EVENT_ON_LOGIN, function(_, player)
|
||||
MoonWellAIO.SchedulePlayerGameMode(player, AIO_INIT_SEND_DELAY_MS)
|
||||
end)
|
||||
@@ -1207,6 +1207,9 @@ public:
|
||||
|
||||
void OnHeal(Unit* healer, Unit* receiver, uint32& gain) override
|
||||
{
|
||||
if (!healer)
|
||||
return;
|
||||
|
||||
if (healer->IsPlayer())
|
||||
sEluna->OnPlayerHeal(healer->ToPlayer(), receiver, gain);
|
||||
|
||||
@@ -1216,6 +1219,9 @@ public:
|
||||
|
||||
void OnDamage(Unit* attacker, Unit* receiver, uint32& damage) override
|
||||
{
|
||||
if (!attacker)
|
||||
return;
|
||||
|
||||
if (attacker->IsPlayer())
|
||||
sEluna->OnPlayerDamage(attacker->ToPlayer(), receiver, damage);
|
||||
|
||||
|
||||
@@ -70,12 +70,13 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_INS_BATTLEGROUND_RANDOM, "INSERT INTO character_battleground_random (guid) VALUES (?)", CONNECTION_ASYNC);
|
||||
|
||||
// Start LoginQueryHolder content
|
||||
PrepareStatement(CHAR_SEL_CHARACTER, "SELECT guid, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, bankSlots, restState, playerFlags, "
|
||||
PrepareStatement(CHAR_SEL_CHARACTER, "SELECT characters.guid, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, bankSlots, restState, playerFlags, "
|
||||
"position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, "
|
||||
"resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, instance_mode_mask, "
|
||||
"arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, todayKills, yesterdayKills, chosenTitle, knownCurrencies, watchedFaction, drunk, "
|
||||
"health, power1, power2, power3, power4, power5, power6, power7, instance_id, talentGroupsCount, activeTalentGroup, exploredZones, equipmentCache, ammoId, "
|
||||
"knownTitles, actionBars, grantableLevels, innTriggerId, extraBonusTalentCount, UNIX_TIMESTAMP(creation_date) FROM characters WHERE guid = ?", CONNECTION_ASYNC);
|
||||
"knownTitles, actionBars, grantableLevels, innTriggerId, extraBonusTalentCount, UNIX_TIMESTAMP(creation_date), COALESCE(mgc.game_mode, 0) "
|
||||
"FROM characters LEFT JOIN mod_gamemodes_characters AS mgc ON characters.guid = mgc.guid WHERE characters.guid = ?", CONNECTION_ASYNC);
|
||||
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_AURAS, "SELECT casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, "
|
||||
"base_amount0, base_amount1, base_amount2, maxDuration, remainTime, remainCharges FROM character_aura WHERE guid = ?", CONNECTION_ASYNC);
|
||||
@@ -113,6 +114,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_RANDOMBG, "SELECT guid FROM character_battleground_random WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_BANNED, "SELECT guid FROM character_banned WHERE guid = ? AND active = 1", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUSREW, "SELECT quest FROM character_queststatus_rewarded WHERE guid = ? AND active = 1", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_REP_CHAR_GAME_MODE, "REPLACE INTO mod_gamemodes_characters (guid, game_mode) VALUES (?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CHAR_GAME_MODE, "DELETE FROM mod_gamemodes_characters WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES, "SELECT instanceId, releaseTime FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_BREW_OF_THE_MONTH, "SELECT lastEventId FROM character_brew_of_the_month WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_REP_BREW_OF_THE_MONTH, "REPLACE INTO character_brew_of_the_month (guid, lastEventId) VALUES (?, ?)", CONNECTION_ASYNC);
|
||||
|
||||
@@ -97,6 +97,8 @@ enum CharacterDatabaseStatements : uint32
|
||||
CHAR_SEL_CHARACTER_RANDOMBG,
|
||||
CHAR_SEL_CHARACTER_BANNED,
|
||||
CHAR_SEL_CHARACTER_QUESTSTATUSREW,
|
||||
CHAR_REP_CHAR_GAME_MODE,
|
||||
CHAR_DEL_CHAR_GAME_MODE,
|
||||
CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES,
|
||||
CHAR_SEL_MAILITEMS,
|
||||
CHAR_SEL_BREW_OF_THE_MONTH,
|
||||
|
||||
@@ -333,7 +333,7 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un
|
||||
if (Player const* player = target->ToPlayer())
|
||||
if (player->GetDeathTimer() != 0)
|
||||
// flag set == must be same team, not set == different team
|
||||
return (player->GetTeamId() == source->GetTeamId()) == (player_dead.own_team_flag != 0);
|
||||
return (player->GetBgTeamId() == source->GetBgTeamId()) == (player_dead.own_team_flag != 0);
|
||||
return false;
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA:
|
||||
return source->HasAuraEffect(aura.spell_id, aura.effect_idx);
|
||||
@@ -389,7 +389,7 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un
|
||||
if (!bg)
|
||||
return false;
|
||||
|
||||
uint32 score = bg->GetTeamScore(source->GetTeamId() == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE);
|
||||
uint32 score = bg->GetTeamScore(source->GetBgTeamId() == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE);
|
||||
return score >= bg_loss_team_score.min_score && score <= bg_loss_team_score.max_score;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT:
|
||||
@@ -462,7 +462,7 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un
|
||||
|
||||
uint32 winnnerScore = bg->GetTeamScore(winnerTeam);
|
||||
uint32 loserScore = bg->GetTeamScore(TeamId(!uint32(winnerTeam)));
|
||||
return source->GetTeamId() == winnerTeam && winnnerScore == teams_scores.winner_score && loserScore == teams_scores.loser_score;
|
||||
return source->GetBgTeamId() == winnerTeam && winnnerScore == teams_scores.winner_score && loserScore == teams_scores.loser_score;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
@@ -635,7 +635,7 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, PreparedQ
|
||||
|
||||
// title achievement rewards are retroactive
|
||||
if (AchievementReward const* reward = sAchievementMgr->GetAchievementReward(achievement))
|
||||
if (uint32 titleId = reward->titleId[Player::TeamIdForRace(GetPlayer()->getRace())])
|
||||
if (uint32 titleId = reward->titleId[uint8(GetPlayer()->GetTeamId())])
|
||||
if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId))
|
||||
if (!GetPlayer()->HasTitle(titleEntry))
|
||||
GetPlayer()->SetTitle(titleEntry);
|
||||
@@ -2448,8 +2448,8 @@ bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria,
|
||||
if (achievement->mapID != -1 && GetPlayer()->GetMapId() != uint32(achievement->mapID))
|
||||
return false;
|
||||
|
||||
if ((achievement->requiredFaction == ACHIEVEMENT_FACTION_HORDE && GetPlayer()->GetTeamId(true) != TEAM_HORDE) ||
|
||||
(achievement->requiredFaction == ACHIEVEMENT_FACTION_ALLIANCE && GetPlayer()->GetTeamId(true) != TEAM_ALLIANCE))
|
||||
if ((achievement->requiredFaction == ACHIEVEMENT_FACTION_HORDE && GetPlayer()->GetTeamId() != TEAM_HORDE) ||
|
||||
(achievement->requiredFaction == ACHIEVEMENT_FACTION_ALLIANCE && GetPlayer()->GetTeamId() != TEAM_ALLIANCE))
|
||||
return false;
|
||||
|
||||
for (uint32 i = 0; i < MAX_CRITERIA_REQUIREMENTS; ++i)
|
||||
|
||||
@@ -430,7 +430,7 @@ namespace lfg
|
||||
{
|
||||
if (!itemRequirement->checkLeaderOnly || !group || group->GetLeaderGUID() == player->GetGUID())
|
||||
{
|
||||
if (itemRequirement->faction == TEAM_NEUTRAL || itemRequirement->faction == player->GetTeamId(true))
|
||||
if (itemRequirement->faction == TEAM_NEUTRAL || itemRequirement->faction == player->GetTeamId())
|
||||
{
|
||||
if (!player->HasItemCount(itemRequirement->id, 1))
|
||||
{
|
||||
@@ -446,7 +446,7 @@ namespace lfg
|
||||
{
|
||||
if (!questRequirement->checkLeaderOnly || !group || group->GetLeaderGUID() == player->GetGUID())
|
||||
{
|
||||
if (questRequirement->faction == TEAM_NEUTRAL || questRequirement->faction == player->GetTeamId(true))
|
||||
if (questRequirement->faction == TEAM_NEUTRAL || questRequirement->faction == player->GetTeamId())
|
||||
{
|
||||
if (!player->GetQuestRewardStatus(questRequirement->id))
|
||||
{
|
||||
@@ -468,7 +468,7 @@ namespace lfg
|
||||
{
|
||||
if (!achievementRequirement->checkLeaderOnly || !group || group->GetLeaderGUID() == player->GetGUID())
|
||||
{
|
||||
if (achievementRequirement->faction == TEAM_NEUTRAL || achievementRequirement->faction == player->GetTeamId(true))
|
||||
if (achievementRequirement->faction == TEAM_NEUTRAL || achievementRequirement->faction == player->GetTeamId())
|
||||
{
|
||||
if (!player->HasAchieved(achievementRequirement->id))
|
||||
{
|
||||
|
||||
@@ -147,6 +147,80 @@ enum CharacterCustomizeFlags
|
||||
CHAR_CUSTOMIZE_FLAG_RACE = 0x00100000 // name, gender, race, etc...
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr uint32 ALLIANCE_TRAITOR_REPUTATION_FACTIONS[] = { 72, 47, 69, 54, 930, 890, 730, 509 };
|
||||
constexpr uint32 HORDE_TRAITOR_REPUTATION_FACTIONS[] = { 76, 81, 68, 530, 911, 889, 729, 510 };
|
||||
constexpr uint32 TRAITOR_REPUTATION_FACTION_COUNT = 8;
|
||||
|
||||
bool IsGameModeEnabled(PlayerGameMode gameMode)
|
||||
{
|
||||
if (gameMode == PLAYER_GAMEMODE_NORMAL)
|
||||
return true;
|
||||
|
||||
if (!sConfigMgr->GetOption<bool>("GameModes.Enable", true))
|
||||
return false;
|
||||
|
||||
switch (gameMode)
|
||||
{
|
||||
case PLAYER_GAMEMODE_TRAITOR:
|
||||
return sConfigMgr->GetOption<bool>("GameModes.Traitor.Enable", true);
|
||||
case PLAYER_GAMEMODE_NORMAL:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
TeamId GetOppositeTeamId(TeamId team)
|
||||
{
|
||||
switch (team)
|
||||
{
|
||||
case TEAM_ALLIANCE:
|
||||
return TEAM_HORDE;
|
||||
case TEAM_HORDE:
|
||||
return TEAM_ALLIANCE;
|
||||
default:
|
||||
return TEAM_NEUTRAL;
|
||||
}
|
||||
}
|
||||
|
||||
PlayerGameMode NormalizeGameModeValue(uint8 gameMode)
|
||||
{
|
||||
return gameMode == PLAYER_GAMEMODE_TRAITOR ? PLAYER_GAMEMODE_TRAITOR : PLAYER_GAMEMODE_NORMAL;
|
||||
}
|
||||
|
||||
PlayerGameMode GameModeFromOutfitId(uint8 outfitId)
|
||||
{
|
||||
if (outfitId == 0)
|
||||
return PLAYER_GAMEMODE_NORMAL;
|
||||
|
||||
// We repurpose the create packet's outfit byte for game mode selection.
|
||||
// The stock client normally sends 0 here, so treat any non-zero custom value
|
||||
// as a request for the only create-time custom mode we currently support.
|
||||
PlayerGameMode gameMode = NormalizeGameModeValue(outfitId);
|
||||
|
||||
if (gameMode == PLAYER_GAMEMODE_NORMAL)
|
||||
gameMode = PLAYER_GAMEMODE_TRAITOR;
|
||||
|
||||
return IsGameModeEnabled(gameMode) ? gameMode : PLAYER_GAMEMODE_NORMAL;
|
||||
}
|
||||
|
||||
uint8 GetRepresentativeRaceForTeam(TeamId team)
|
||||
{
|
||||
return team == TEAM_HORDE ? RACE_ORC : RACE_HUMAN;
|
||||
}
|
||||
|
||||
PlayerInfo const* GetRepresentativePlayerInfoForTeam(TeamId team, uint8 classId)
|
||||
{
|
||||
uint8 representativeRace = GetRepresentativeRaceForTeam(team);
|
||||
|
||||
if (PlayerInfo const* info = sObjectMgr->GetPlayerInfo(representativeRace, classId))
|
||||
return info;
|
||||
|
||||
return sObjectMgr->GetPlayerInfo(representativeRace, CLASS_WARRIOR);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32 copseReclaimDelay[MAX_DEATH_COUNT] = { 30, 60, 120 };
|
||||
|
||||
// we can disable this warning for this since it only
|
||||
@@ -492,6 +566,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
|
||||
// also do it in Player::BuildEnumData, Player::LoadFromDB
|
||||
|
||||
Object::_Create(guidlow, 0, HighGuid::Player);
|
||||
SetGameMode(GameModeFromOutfitId(m_outfitId));
|
||||
|
||||
m_name = createInfo->Name;
|
||||
|
||||
@@ -506,8 +581,6 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
|
||||
for (uint8 i = 0; i < PLAYER_SLOTS_COUNT; i++)
|
||||
m_items[i] = nullptr;
|
||||
|
||||
Relocate(info->positionX, info->positionY, info->positionZ, info->orientation);
|
||||
|
||||
ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(createInfo->Class);
|
||||
if (!cEntry)
|
||||
{
|
||||
@@ -516,8 +589,6 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
|
||||
return false;
|
||||
}
|
||||
|
||||
SetMap(sMapMgr->CreateMap(info->mapId, this));
|
||||
|
||||
uint8 powertype = cEntry->powerType;
|
||||
|
||||
SetObjectScale(1.0f);
|
||||
@@ -525,8 +596,6 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
|
||||
m_realRace = createInfo->Race; // set real race flag
|
||||
m_race = createInfo->Race; // set real race flag
|
||||
|
||||
SetFactionForRace(createInfo->Race);
|
||||
|
||||
if (!IsValidGender(createInfo->Gender))
|
||||
{
|
||||
LOG_ERROR("entities.player", "Player::Create: Possible hacking-attempt: Account {} tried creating a character named '{}' with an invalid gender ({}) - refusing to do so",
|
||||
@@ -535,8 +604,14 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
|
||||
}
|
||||
|
||||
uint32 RaceClassGender = (createInfo->Race) | (createInfo->Class << 8) | (createInfo->Gender << 16);
|
||||
|
||||
SetUInt32Value(UNIT_FIELD_BYTES_0, (RaceClassGender | (powertype << 24)));
|
||||
|
||||
SetFactionForRace(createInfo->Race);
|
||||
|
||||
WorldLocation startPosition = GetStartPosition();
|
||||
Relocate(startPosition);
|
||||
SetMap(sMapMgr->CreateMap(startPosition.GetMapId(), this));
|
||||
|
||||
InitDisplayIds();
|
||||
if (sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_PVP || sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_RPPVP)
|
||||
{
|
||||
@@ -4068,6 +4143,10 @@ void Player::DeleteFromDB(ObjectGuid::LowType lowGuid, uint32 accountId, bool up
|
||||
stmt->SetData(0, lowGuid);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GAME_MODE);
|
||||
stmt->SetData(0, lowGuid);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_ACCOUNT_DATA);
|
||||
stmt->SetData(0, lowGuid);
|
||||
trans->Append(stmt);
|
||||
@@ -5853,17 +5932,46 @@ TeamId Player::TeamIdForRace(uint8 race)
|
||||
|
||||
void Player::SetFactionForRace(uint8 race)
|
||||
{
|
||||
m_team = TeamIdForRace(race);
|
||||
TeamId nativeTeam = TeamIdForRace(race);
|
||||
m_team = IsTraitor() ? GetOppositeTeamId(nativeTeam) : nativeTeam;
|
||||
|
||||
sScriptMgr->OnPlayerUpdateFaction(this);
|
||||
|
||||
if (GetTeamId(true) != GetTeamId())
|
||||
return;
|
||||
|
||||
ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race);
|
||||
uint8 factionRace = IsTraitor() ? GetRepresentativeRaceForTeam(m_team) : race;
|
||||
ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(factionRace);
|
||||
SetFaction(rEntry ? rEntry->FactionID : 0);
|
||||
}
|
||||
|
||||
PlayerGameMode Player::ResolveGameModeFromStorage(uint32 playerFlags, uint8 gameMode)
|
||||
{
|
||||
PlayerGameMode resolvedGameMode = NormalizeGameModeValue(gameMode);
|
||||
|
||||
if (resolvedGameMode == PLAYER_GAMEMODE_NORMAL && (playerFlags & PLAYER_FLAGS_TRAITOR))
|
||||
resolvedGameMode = PLAYER_GAMEMODE_TRAITOR;
|
||||
|
||||
return IsGameModeEnabled(resolvedGameMode) ? resolvedGameMode : PLAYER_GAMEMODE_NORMAL;
|
||||
}
|
||||
|
||||
PlayerInfo const* Player::GetStartPlayerInfo() const
|
||||
{
|
||||
if (IsTraitor())
|
||||
return GetRepresentativePlayerInfoForTeam(GetTeamId(), getClass());
|
||||
|
||||
return sObjectMgr->GetPlayerInfo(getRace(true), getClass());
|
||||
}
|
||||
|
||||
void Player::SetGameMode(PlayerGameMode gameMode)
|
||||
{
|
||||
m_gameMode = NormalizeGameModeValue(static_cast<uint8>(gameMode));
|
||||
if (!IsGameModeEnabled(m_gameMode))
|
||||
m_gameMode = PLAYER_GAMEMODE_NORMAL;
|
||||
|
||||
if (m_gameMode == PLAYER_GAMEMODE_TRAITOR)
|
||||
SetPlayerFlag(PLAYER_FLAGS_TRAITOR);
|
||||
else
|
||||
RemovePlayerFlag(PLAYER_FLAGS_TRAITOR);
|
||||
}
|
||||
|
||||
ReputationRank Player::GetReputationRank(uint32 faction) const
|
||||
{
|
||||
FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction);
|
||||
@@ -6089,6 +6197,78 @@ void Player::RewardReputation(Quest const* quest)
|
||||
}
|
||||
}
|
||||
|
||||
void Player::ApplyTraitorReputationState()
|
||||
{
|
||||
if (!IsTraitor())
|
||||
return;
|
||||
|
||||
auto normalizeFactionState = [this](FactionEntry const* factionEntry, bool visible, bool atWar)
|
||||
{
|
||||
if (!factionEntry || factionEntry->reputationListID < 0)
|
||||
return;
|
||||
|
||||
FactionState* factionState = const_cast<FactionState*>(GetReputationMgr().GetState(factionEntry));
|
||||
if (!factionState)
|
||||
return;
|
||||
|
||||
factionState->Flags &= ~(FACTION_FLAG_VISIBLE | FACTION_FLAG_HIDDEN | FACTION_FLAG_INVISIBLE_FORCED |
|
||||
FACTION_FLAG_PEACE_FORCED | FACTION_FLAG_INACTIVE);
|
||||
|
||||
if (visible)
|
||||
factionState->Flags |= FACTION_FLAG_VISIBLE;
|
||||
else
|
||||
factionState->Flags |= FACTION_FLAG_HIDDEN | FACTION_FLAG_INVISIBLE_FORCED;
|
||||
|
||||
if (atWar)
|
||||
factionState->Flags |= FACTION_FLAG_AT_WAR;
|
||||
else
|
||||
factionState->Flags &= ~FACTION_FLAG_AT_WAR;
|
||||
|
||||
factionState->needSend = true;
|
||||
factionState->needSave = true;
|
||||
};
|
||||
|
||||
auto setFactionStanding = [this, &normalizeFactionState](uint32 factionId, int32 targetDisplayed, bool visible, bool atWar)
|
||||
{
|
||||
FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionId);
|
||||
if (!factionEntry)
|
||||
return;
|
||||
|
||||
GetReputationMgr().SetOneFactionReputation(factionEntry, static_cast<float>(targetDisplayed), false);
|
||||
normalizeFactionState(factionEntry, visible, atWar);
|
||||
};
|
||||
|
||||
auto normalizeFactionAndParent = [&normalizeFactionState](uint32 factionId, bool visible, bool atWar)
|
||||
{
|
||||
if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionId))
|
||||
{
|
||||
normalizeFactionState(factionEntry, visible, atWar);
|
||||
|
||||
if (factionEntry->team)
|
||||
normalizeFactionState(sFactionStore.LookupEntry(factionEntry->team), visible, false);
|
||||
}
|
||||
};
|
||||
|
||||
TeamId nativeTeam = GetTeamId(true);
|
||||
uint32 const* friendlyFactions = nativeTeam == TEAM_ALLIANCE ? HORDE_TRAITOR_REPUTATION_FACTIONS : ALLIANCE_TRAITOR_REPUTATION_FACTIONS;
|
||||
uint32 const* hostileFactions = nativeTeam == TEAM_ALLIANCE ? ALLIANCE_TRAITOR_REPUTATION_FACTIONS : HORDE_TRAITOR_REPUTATION_FACTIONS;
|
||||
|
||||
if (HasAtLoginFlag(AT_LOGIN_FIRST))
|
||||
{
|
||||
for (uint32 i = 0; i < TRAITOR_REPUTATION_FACTION_COUNT; ++i)
|
||||
setFactionStanding(friendlyFactions[i], 0, true, false);
|
||||
|
||||
for (uint32 i = 0; i < TRAITOR_REPUTATION_FACTION_COUNT; ++i)
|
||||
setFactionStanding(hostileFactions[i], -6000, false, true);
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < TRAITOR_REPUTATION_FACTION_COUNT; ++i)
|
||||
{
|
||||
normalizeFactionAndParent(friendlyFactions[i], true, false);
|
||||
normalizeFactionAndParent(hostileFactions[i], false, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::RewardExtraBonusTalentPoints(uint32 bonusTalentPoints)
|
||||
{
|
||||
if (bonusTalentPoints)
|
||||
@@ -10304,7 +10484,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
|
||||
// only one mount ID for both sides. Probably not good to use 315 in case DBC nodes
|
||||
// change but I couldn't find a suitable alternative. OK to use class because only DK
|
||||
// can use this taxi.
|
||||
uint32 mount_display_id = sObjectMgr->GetTaxiMountDisplayId(sourcenode, GetTeamId(true), npc == nullptr || (sourcenode == 315 && IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TAXI)));
|
||||
uint32 mount_display_id = sObjectMgr->GetTaxiMountDisplayId(sourcenode, GetTeamId(), npc == nullptr || (sourcenode == 315 && IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TAXI)));
|
||||
|
||||
// in spell case allow 0 model
|
||||
if ((mount_display_id == 0 && spellid == 0) || sourcepath == 0)
|
||||
@@ -10399,7 +10579,7 @@ void Player::ContinueTaxiFlight()
|
||||
|
||||
LOG_DEBUG("entities.unit", "WORLD: Restart character {} taxi flight", GetGUID().ToString());
|
||||
|
||||
uint32 mountDisplayId = sObjectMgr->GetTaxiMountDisplayId(sourceNode, GetTeamId(true), true);
|
||||
uint32 mountDisplayId = sObjectMgr->GetTaxiMountDisplayId(sourceNode, GetTeamId(), true);
|
||||
if (!mountDisplayId)
|
||||
return;
|
||||
|
||||
@@ -10678,7 +10858,7 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsGameMaster() && ((pProto->HasFlag2(ITEM_FLAG2_FACTION_HORDE) && GetTeamId(true) == TEAM_ALLIANCE) || (pProto->HasFlag2(ITEM_FLAG2_FACTION_ALLIANCE) && GetTeamId(true) == TEAM_HORDE)))
|
||||
if (!IsGameMaster() && ((pProto->HasFlag2(ITEM_FLAG2_FACTION_HORDE) && GetTeamId() == TEAM_ALLIANCE) || (pProto->HasFlag2(ITEM_FLAG2_FACTION_ALLIANCE) && GetTeamId() == TEAM_HORDE)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -11341,7 +11521,7 @@ void Player::ReportedAfkBy(Player* reporter)
|
||||
|
||||
WorldLocation Player::GetStartPosition() const
|
||||
{
|
||||
PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(true), getClass());
|
||||
PlayerInfo const* info = GetStartPlayerInfo();
|
||||
uint32 mapId = info->mapId;
|
||||
if (IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_INIT) && HasSpell(50977))
|
||||
return WorldLocation(0, 2352.0f, -5709.0f, 154.5f, 0.0f);
|
||||
@@ -14701,6 +14881,7 @@ void Player::_SaveEntryPoint(CharacterDatabaseTransaction trans)
|
||||
stmt->SetData(7, m_entryPointData.taxiPath[1]);
|
||||
stmt->SetData(8, m_entryPointData.mountSpell);
|
||||
trans->Append(stmt);
|
||||
|
||||
}
|
||||
|
||||
void Player::DeleteEquipmentSet(uint64 setGuid)
|
||||
@@ -14768,6 +14949,25 @@ void Player::_SaveCharacter(bool create, CharacterDatabaseTransaction trans)
|
||||
uint8 index = 0;
|
||||
|
||||
auto finiteAlways = [](float f) { return std::isfinite(f) ? f : 0.0f; };
|
||||
PlayerGameMode persistedGameMode = GetGameMode();
|
||||
|
||||
// Character enum and login restore traitor mode from persisted storage, not from the
|
||||
// transient create packet. Re-derive the initial mode from the raw create byte before
|
||||
// the first save in case later create initialization has reset the in-memory state.
|
||||
if (create && persistedGameMode == PLAYER_GAMEMODE_NORMAL && m_outfitId != 0)
|
||||
{
|
||||
persistedGameMode = GameModeFromOutfitId(m_outfitId);
|
||||
|
||||
if (persistedGameMode != GetGameMode())
|
||||
{
|
||||
SetGameMode(persistedGameMode);
|
||||
SetFactionForRace(getRace(true));
|
||||
}
|
||||
}
|
||||
|
||||
uint32 playerFlagsForSave = GetPlayerFlags();
|
||||
if (create && persistedGameMode == PLAYER_GAMEMODE_TRAITOR)
|
||||
playerFlagsForSave |= PLAYER_FLAGS_TRAITOR;
|
||||
|
||||
if (create)
|
||||
{
|
||||
@@ -14790,7 +14990,7 @@ void Player::_SaveCharacter(bool create, CharacterDatabaseTransaction trans)
|
||||
stmt->SetData(index++, GetByteValue(PLAYER_BYTES_2, 0));
|
||||
stmt->SetData(index++, GetByteValue(PLAYER_BYTES_2, 2));
|
||||
stmt->SetData(index++, GetByteValue(PLAYER_BYTES_2, 3));
|
||||
stmt->SetData(index++, (uint32)GetPlayerFlags());
|
||||
stmt->SetData(index++, playerFlagsForSave);
|
||||
stmt->SetData(index++, (uint16)GetMapId());
|
||||
stmt->SetData(index++, (uint32)GetInstanceId());
|
||||
stmt->SetData(index++, (uint8(GetDungeonDifficulty()) | uint8(GetRaidDifficulty()) << 4));
|
||||
@@ -14908,7 +15108,7 @@ void Player::_SaveCharacter(bool create, CharacterDatabaseTransaction trans)
|
||||
stmt->SetData(index++, GetByteValue(PLAYER_BYTES_2, 0));
|
||||
stmt->SetData(index++, GetByteValue(PLAYER_BYTES_2, 2));
|
||||
stmt->SetData(index++, GetByteValue(PLAYER_BYTES_2, 3));
|
||||
stmt->SetData(index++, GetPlayerFlags());
|
||||
stmt->SetData(index++, playerFlagsForSave);
|
||||
|
||||
if (!IsBeingTeleported())
|
||||
{
|
||||
@@ -15036,6 +15236,20 @@ void Player::_SaveCharacter(bool create, CharacterDatabaseTransaction trans)
|
||||
}
|
||||
|
||||
trans->Append(stmt);
|
||||
|
||||
if (persistedGameMode == PLAYER_GAMEMODE_TRAITOR)
|
||||
{
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_GAME_MODE);
|
||||
stmt->SetData(0, GetGUID().GetCounter());
|
||||
stmt->SetData(1, uint8(persistedGameMode));
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GAME_MODE);
|
||||
stmt->SetData(0, GetGUID().GetCounter());
|
||||
}
|
||||
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
void Player::_LoadGlyphs(PreparedQueryResult result)
|
||||
|
||||
@@ -454,6 +454,13 @@ enum DrunkenState
|
||||
|
||||
#define MAX_DRUNKEN 4
|
||||
|
||||
enum PlayerGameMode : uint8
|
||||
{
|
||||
PLAYER_GAMEMODE_NORMAL = 0,
|
||||
PLAYER_GAMEMODE_TRAITOR = 1,
|
||||
PLAYER_GAMEMODE_MAX
|
||||
};
|
||||
|
||||
enum PlayerFlags : uint32
|
||||
{
|
||||
PLAYER_FLAGS_GROUP_LEADER = 0x00000001,
|
||||
@@ -1156,7 +1163,7 @@ public:
|
||||
PlayerSocial* GetSocial() { return m_social; }
|
||||
|
||||
PlayerTaxi m_taxi;
|
||||
void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(getRace(), getClass(), GetLevel()); }
|
||||
void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(IsTraitor() ? (GetTeamId() == TEAM_ALLIANCE ? RACE_HUMAN : RACE_ORC) : getRace(), getClass(), GetLevel()); }
|
||||
bool ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc = nullptr, uint32 spellid = 1);
|
||||
bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 1);
|
||||
void CleanupAfterTaxiFlight();
|
||||
@@ -2126,7 +2133,13 @@ public:
|
||||
void CheckAreaExploreAndOutdoor();
|
||||
|
||||
static TeamId TeamIdForRace(uint8 race);
|
||||
[[nodiscard]] static PlayerGameMode ResolveGameModeFromStorage(uint32 playerFlags, uint8 gameMode);
|
||||
[[nodiscard]] TeamId GetTeamId(bool original = false) const { return original ? TeamIdForRace(getRace(true)) : m_team; };
|
||||
[[nodiscard]] PlayerGameMode GetGameMode() const { return m_gameMode; }
|
||||
[[nodiscard]] bool HasGameMode(PlayerGameMode gameMode) const { return m_gameMode == gameMode; }
|
||||
[[nodiscard]] bool IsTraitor() const { return HasGameMode(PLAYER_GAMEMODE_TRAITOR); }
|
||||
[[nodiscard]] PlayerInfo const* GetStartPlayerInfo() const;
|
||||
void SetGameMode(PlayerGameMode gameMode);
|
||||
void SetFactionForRace(uint8 race);
|
||||
void setTeamId(TeamId teamid) { m_team = teamid; };
|
||||
|
||||
@@ -2150,6 +2163,7 @@ public:
|
||||
[[nodiscard]] ReputationRank GetReputationRank(uint32 faction_id) const;
|
||||
void RewardReputation(Unit* victim);
|
||||
void RewardReputation(Quest const* quest);
|
||||
void ApplyTraitorReputationState();
|
||||
|
||||
float CalculateReputationGain(ReputationSource source, uint32 creatureOrQuestLevel, float rep, int32 faction, bool noQuestBonus = false);
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
#include "Util.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include <cmath>
|
||||
|
||||
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
|
||||
// however, for some reasons removing it would cause a damn linking issue
|
||||
@@ -2378,12 +2379,12 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const
|
||||
return EQUIP_ERR_ITEM_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (proto->HasFlag2(ITEM_FLAG2_FACTION_HORDE) && GetTeamId(true) != TEAM_HORDE)
|
||||
if (proto->HasFlag2(ITEM_FLAG2_FACTION_HORDE) && GetTeamId() != TEAM_HORDE)
|
||||
{
|
||||
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
|
||||
}
|
||||
|
||||
if (proto->HasFlag2(ITEM_FLAG2_FACTION_ALLIANCE) && GetTeamId(true) != TEAM_ALLIANCE)
|
||||
if (proto->HasFlag2(ITEM_FLAG2_FACTION_ALLIANCE) && GetTeamId() != TEAM_ALLIANCE)
|
||||
{
|
||||
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
|
||||
}
|
||||
@@ -5014,8 +5015,8 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
|
||||
//"arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, todayKills, yesterdayKills, chosenTitle, knownCurrencies, watchedFaction, drunk, "
|
||||
// 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
||||
//"health, power1, power2, power3, power4, power5, power6, power7, instance_id, talentGroupsCount, activeTalentGroup, exploredZones, equipmentCache, ammoId, knownTitles,
|
||||
// 70 71 72 73 74
|
||||
//"actionBars, grantableLevels, innTriggerId, extraBonusTalentCount, UNIX_TIMESTAMP(creation_date) FROM characters WHERE guid = '{}'", guid);
|
||||
// 70 71 72 73 74 75
|
||||
//"actionBars, grantableLevels, innTriggerId, extraBonusTalentCount, UNIX_TIMESTAMP(creation_date), game_mode FROM characters WHERE guid = '{}'", guid);
|
||||
PreparedQueryResult result = holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_FROM);
|
||||
|
||||
if (!result)
|
||||
@@ -5093,6 +5094,8 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
|
||||
|
||||
// load character creation date, relevant for achievements of type average
|
||||
SetCreationTime(fields[74].Get<Seconds>());
|
||||
PlayerGameMode storedGameMode = ResolveGameModeFromStorage(fields[16].Get<uint32>(), fields[75].Get<uint8>());
|
||||
SetGameMode(storedGameMode);
|
||||
|
||||
// load achievements before anything else to prevent multiple gains for the same achievement/criteria on every loading (as loading does call UpdateAchievementCriteria)
|
||||
m_achievementMgr->LoadFromDB(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_OFFLINE_ACHIEVEMENTS_UPDATES));
|
||||
@@ -5112,6 +5115,7 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
|
||||
SetByteValue(PLAYER_BYTES_3, 0, fields[5].Get<uint8>());
|
||||
SetByteValue(PLAYER_BYTES_3, 1, fields[54].Get<uint8>());
|
||||
ReplaceAllPlayerFlags((PlayerFlags)fields[16].Get<uint32>());
|
||||
SetGameMode(storedGameMode);
|
||||
SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fields[53].Get<uint32>());
|
||||
|
||||
SetUInt64Value(PLAYER_FIELD_KNOWN_CURRENCIES, fields[52].Get<uint64>());
|
||||
@@ -5149,12 +5153,22 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
|
||||
|
||||
InitPrimaryProfessions(); // to max set before any spell loaded
|
||||
|
||||
bool isFirstLogin = (fields[38].Get<uint16>() & AT_LOGIN_FIRST) != 0;
|
||||
|
||||
// init saved position, and fix it later if problematic
|
||||
int32 transLowGUID = fields[35].Get<int32>();
|
||||
Relocate(fields[17].Get<float>(), fields[18].Get<float>(), fields[19].Get<float>(), fields[21].Get<float>());
|
||||
uint32 mapId = fields[20].Get<uint16>();
|
||||
uint32 instanceId = fields[63].Get<uint32>();
|
||||
|
||||
if (isFirstLogin && IsTraitor())
|
||||
{
|
||||
WorldLocation startPosition = GetStartPosition();
|
||||
Relocate(startPosition);
|
||||
mapId = startPosition.GetMapId();
|
||||
instanceId = 0;
|
||||
}
|
||||
|
||||
uint32 dungeonDiff = fields[43].Get<uint8>() & 0x0F;
|
||||
if (dungeonDiff >= MAX_DUNGEON_DIFFICULTY)
|
||||
dungeonDiff = DUNGEON_DIFFICULTY_NORMAL;
|
||||
@@ -5311,7 +5325,7 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
|
||||
else if (!taxi_nodes.empty())
|
||||
{
|
||||
instanceId = 0;
|
||||
if (!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes, GetTeamId(true)))
|
||||
if (!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes, GetTeamId()))
|
||||
{
|
||||
// xinef: could no load valid data for taxi, relocate to homebind and clear
|
||||
m_taxi.ClearTaxiDestinations();
|
||||
@@ -6851,7 +6865,7 @@ bool Player::Satisfy(DungeonProgressionRequirements const* ar, uint32 target_map
|
||||
missingItems = &missingLeaderItems;
|
||||
}
|
||||
|
||||
if (itemRequirement->faction == TEAM_NEUTRAL || itemRequirement->faction == checkPlayer->GetTeamId(true))
|
||||
if (itemRequirement->faction == TEAM_NEUTRAL || itemRequirement->faction == checkPlayer->GetTeamId())
|
||||
{
|
||||
if (!checkPlayer->HasItemCount(itemRequirement->id, 1))
|
||||
{
|
||||
@@ -6873,7 +6887,7 @@ bool Player::Satisfy(DungeonProgressionRequirements const* ar, uint32 target_map
|
||||
missingAchievements = &missingLeaderAchievements;
|
||||
}
|
||||
|
||||
if (achievementRequirement->faction == TEAM_NEUTRAL || achievementRequirement->faction == GetTeamId(true))
|
||||
if (achievementRequirement->faction == TEAM_NEUTRAL || achievementRequirement->faction == GetTeamId())
|
||||
{
|
||||
if (!checkPlayer || !checkPlayer->HasAchieved(achievementRequirement->id))
|
||||
{
|
||||
@@ -6895,7 +6909,7 @@ bool Player::Satisfy(DungeonProgressionRequirements const* ar, uint32 target_map
|
||||
missingQuests = &missingLeaderQuests;
|
||||
}
|
||||
|
||||
if (questRequirement->faction == TEAM_NEUTRAL || questRequirement->faction == checkPlayer->GetTeamId(true))
|
||||
if (questRequirement->faction == TEAM_NEUTRAL || questRequirement->faction == checkPlayer->GetTeamId())
|
||||
{
|
||||
if (!checkPlayer->GetQuestRewardStatus(questRequirement->id))
|
||||
{
|
||||
@@ -7082,8 +7096,9 @@ bool Player::CheckInstanceCount(uint32 instanceId) const
|
||||
|
||||
bool Player::_LoadHomeBind(PreparedQueryResult result)
|
||||
{
|
||||
PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(true), getClass());
|
||||
if (!info)
|
||||
PlayerInfo const* info = GetStartPlayerInfo();
|
||||
PlayerInfo const* nativeInfo = sObjectMgr->GetPlayerInfo(getRace(true), getClass());
|
||||
if (!info || !nativeInfo)
|
||||
{
|
||||
LOG_ERROR("entities.player", "Player (Name {}) has incorrect race/class pair. Can't be loaded.", GetName());
|
||||
return false;
|
||||
@@ -7115,6 +7130,25 @@ bool Player::_LoadHomeBind(PreparedQueryResult result)
|
||||
}
|
||||
}
|
||||
|
||||
if (ok && IsTraitor())
|
||||
{
|
||||
auto sameCoord = [](float left, float right) { return std::fabs(left - right) < 0.01f; };
|
||||
bool matchesNativeHomebind = m_homebindMapId == nativeInfo->mapId &&
|
||||
m_homebindAreaId == nativeInfo->areaId &&
|
||||
sameCoord(m_homebindX, nativeInfo->positionX) &&
|
||||
sameCoord(m_homebindY, nativeInfo->positionY) &&
|
||||
sameCoord(m_homebindZ, nativeInfo->positionZ);
|
||||
|
||||
bool matchesEffectiveHomebind = m_homebindMapId == info->mapId &&
|
||||
m_homebindAreaId == info->areaId &&
|
||||
sameCoord(m_homebindX, info->positionX) &&
|
||||
sameCoord(m_homebindY, info->positionY) &&
|
||||
sameCoord(m_homebindZ, info->positionZ);
|
||||
|
||||
if (matchesNativeHomebind && !matchesEffectiveHomebind)
|
||||
SetHomebind(WorldLocation(info->mapId, info->positionX, info->positionY, info->positionZ, 0.0f), info->areaId);
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
m_homebindMapId = info->mapId;
|
||||
|
||||
@@ -548,7 +548,9 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((haveSameRace && skipCinematics == 1) || skipCinematics == 2)
|
||||
if (newChar->IsTraitor())
|
||||
newChar->setCinematic(1);
|
||||
else if ((haveSameRace && skipCinematics == 1) || skipCinematics == 2)
|
||||
newChar->setCinematic(1); // not show intro
|
||||
|
||||
newChar->SetAtLoginFlag(AT_LOGIN_FIRST); // First login
|
||||
@@ -558,6 +560,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
|
||||
|
||||
// Player created, save it now
|
||||
newChar->SaveToDB(characterTransaction, true, false);
|
||||
|
||||
createInfo->CharCount++;
|
||||
|
||||
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM);
|
||||
|
||||
@@ -446,12 +446,12 @@ bool LootItem::AllowedForPlayer(Player const* player, ObjectGuid source) const
|
||||
}
|
||||
|
||||
// not show loot for not own team
|
||||
if (pProto->HasFlag2(ITEM_FLAG2_FACTION_HORDE) && player->GetTeamId(true) != TEAM_HORDE)
|
||||
if (pProto->HasFlag2(ITEM_FLAG2_FACTION_HORDE) && player->GetTeamId() != TEAM_HORDE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pProto->HasFlag2(ITEM_FLAG2_FACTION_ALLIANCE) && player->GetTeamId(true) != TEAM_ALLIANCE)
|
||||
if (pProto->HasFlag2(ITEM_FLAG2_FACTION_ALLIANCE) && player->GetTeamId() != TEAM_ALLIANCE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user