Merge branch 'azerothcore:master' into test-staging
This commit is contained in:
@@ -358,6 +358,10 @@ bool CreatureAI::UpdateVictim()
|
||||
return false;
|
||||
}
|
||||
|
||||
// Charmed creatures: the charmer controls target selection, don't interfere
|
||||
if (me->IsCharmed())
|
||||
return me->GetVictim() != nullptr;
|
||||
|
||||
if (!me->HasReactState(REACT_PASSIVE))
|
||||
{
|
||||
if (Unit* victim = me->SelectVictim())
|
||||
|
||||
@@ -911,7 +911,7 @@ void SmartAI::AttackStart(Unit* who)
|
||||
return;
|
||||
}
|
||||
|
||||
if (who && me->Attack(who, me->IsWithinMeleeRange(who)))
|
||||
if (who && me->Attack(who, mCanAutoAttack))
|
||||
{
|
||||
if (!me->HasUnitState(UNIT_STATE_NO_COMBAT_MOVEMENT))
|
||||
{
|
||||
|
||||
@@ -2054,6 +2054,8 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_ACTION_WORLD_SCRIPT:
|
||||
case SMART_ACTION_SET_GOSSIP_MENU:
|
||||
case SMART_ACTION_SUMMON_GAMEOBJECT_GROUP:
|
||||
case SMART_ACTION_SPAWN_SPAWNGROUP:
|
||||
case SMART_ACTION_DESPAWN_SPAWNGROUP:
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
|
||||
|
||||
@@ -1118,7 +1118,7 @@ void BattlegroundSA::UpdateDemolisherSpawns()
|
||||
BG_SA_NpcSpawnlocs[i][2], BG_SA_NpcSpawnlocs[i][3]);
|
||||
|
||||
Demolisher->SetVisible(true);
|
||||
Demolisher->Respawn();
|
||||
Demolisher->Respawn(true);
|
||||
DemoliserRespawnList.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,6 +591,12 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
|
||||
condMeets = unit->IsCharmed();
|
||||
break;
|
||||
}
|
||||
case CONDITION_UNIT_IN_COMBAT:
|
||||
{
|
||||
if (Unit* unit = object->ToUnit())
|
||||
condMeets = unit->IsInCombat();
|
||||
break;
|
||||
}
|
||||
case CONDITION_WORLD_SCRIPT:
|
||||
{
|
||||
condMeets = sWorldState->IsConditionFulfilled(ConditionValue1, ConditionValue2);
|
||||
@@ -804,6 +810,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition()
|
||||
case CONDITION_CHARMED:
|
||||
mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
|
||||
break;
|
||||
case CONDITION_UNIT_IN_COMBAT:
|
||||
mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
|
||||
break;
|
||||
case CONDITION_PLAYER_QUEUED_RANDOM_DUNGEON:
|
||||
mask |= GRID_MAP_TYPE_MASK_PLAYER;
|
||||
break;
|
||||
@@ -834,6 +843,7 @@ uint32 Condition::GetMaxAvailableConditionTargets()
|
||||
case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT:
|
||||
case CONDITION_SOURCE_TYPE_GOSSIP_MENU:
|
||||
case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION:
|
||||
case CONDITION_SOURCE_TYPE_GOSSIP_HELLO:
|
||||
case CONDITION_SOURCE_TYPE_NPC_VENDOR:
|
||||
case CONDITION_SOURCE_TYPE_SPELL_PROC:
|
||||
case CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY:
|
||||
@@ -2624,6 +2634,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
|
||||
case CONDITION_TAXI:
|
||||
case CONDITION_IN_WATER:
|
||||
case CONDITION_CHARMED:
|
||||
case CONDITION_UNIT_IN_COMBAT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -89,8 +89,9 @@ enum ConditionTypes
|
||||
CONDITION_WORLD_SCRIPT = 103, // conditionId state 0 true if WorldState::IsConditionFulfilled returns true
|
||||
CONDITION_AI_DATA = 104, // dataId value 0 true if AI::GetData returns value
|
||||
CONDITION_PLAYER_QUEUED_RANDOM_DUNGEON = 105, // checkDifficulty difficulty 0 true if player is queued for a random dungeon via RDF
|
||||
CONDITION_UNIT_IN_COMBAT = 106, // 0 0 0 true if unit is engaged in combat
|
||||
|
||||
CONDITION_AC_END = 106 // placeholder
|
||||
CONDITION_AC_END = 107 // placeholder
|
||||
};
|
||||
|
||||
/*! Documentation on implementing a new ConditionSourceType:
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
KillRewarder::KillRewarder(Player* killer, Unit* victim, bool isBattleGround) :
|
||||
// 1. Initialize internal variables to default values.
|
||||
_killer(killer), _victim(victim), _group(killer->GetGroup()),
|
||||
_groupRate(1.0f), _maxNotGrayMember(nullptr), _count(0), _aliveSumLevel(0), _sumLevel(0), _xp(0),
|
||||
_groupRate(1.0f), _maxNotGrayMember(nullptr), _maxNotGrayMemberLevel(0), _count(0), _aliveSumLevel(0), _sumLevel(0), _xp(0),
|
||||
_isFullXP(false), _maxLevel(0), _isBattleGround(isBattleGround), _isPvP(false)
|
||||
{
|
||||
// mark the credit as pvp if victim is player
|
||||
@@ -89,7 +89,7 @@ void KillRewarder::_InitGroupData()
|
||||
if (Player* member = itr->GetSource())
|
||||
if ((_killer == member || member->IsAtGroupRewardDistance(_victim)))
|
||||
{
|
||||
const uint8 lvl = member->GetLevel();
|
||||
const uint8 lvl = _GetPlayerLevel(member);
|
||||
if (member->IsAlive())
|
||||
{
|
||||
// 2.1. _count - number of alive group members within reward distance;
|
||||
@@ -104,9 +104,10 @@ void KillRewarder::_InitGroupData()
|
||||
// 2.4. _maxNotGrayMember - maximum level of alive group member within reward distance,
|
||||
// for whom victim is not gray;
|
||||
uint32 grayLevel = Acore::XP::GetGrayLevel(lvl);
|
||||
if (_victim->GetLevel() > grayLevel && (!_maxNotGrayMember || _maxNotGrayMember->GetLevel() < lvl))
|
||||
if (_victim->GetLevel() > grayLevel && (!_maxNotGrayMember || _maxNotGrayMemberLevel < lvl))
|
||||
{
|
||||
_maxNotGrayMember = member;
|
||||
_maxNotGrayMemberLevel = lvl;
|
||||
}
|
||||
}
|
||||
// 2.5. _sumLevel - sum of levels of group members within reward distance;
|
||||
@@ -114,7 +115,7 @@ void KillRewarder::_InitGroupData()
|
||||
}
|
||||
// 2.6. _isFullXP - flag identifying that for all group members victim is not gray,
|
||||
// so 100% XP will be rewarded (50% otherwise).
|
||||
_isFullXP = _maxNotGrayMember && (_maxLevel == _maxNotGrayMember->GetLevel());
|
||||
_isFullXP = _maxNotGrayMember && (_maxLevel == _maxNotGrayMemberLevel);
|
||||
}
|
||||
else
|
||||
_count = 1;
|
||||
@@ -153,7 +154,7 @@ void KillRewarder::_RewardXP(Player* player, float rate)
|
||||
// * set to 0 if player's level is more than maximum level of not gray member;
|
||||
// * cut XP in half if _isFullXP is false.
|
||||
if (_maxNotGrayMember && player->IsAlive() &&
|
||||
_maxNotGrayMember->GetLevel() >= player->GetLevel())
|
||||
_maxNotGrayMemberLevel >= _GetPlayerLevel(player))
|
||||
xp = _isFullXP ?
|
||||
uint32(xp * rate) : // Reward FULL XP if all group members are not gray.
|
||||
uint32(xp * rate / 2) + 1; // Reward only HALF of XP if some of group members are gray.
|
||||
@@ -208,8 +209,8 @@ void KillRewarder::_RewardPlayer(Player* player, bool isDungeon)
|
||||
// Give reputation and kill credit only in PvE.
|
||||
if (!_isPvP || _isBattleGround)
|
||||
{
|
||||
float xpRate = _group ? _groupRate * float(player->GetLevel()) / _aliveSumLevel : /*Personal rate is 100%.*/ 1.0f; // Group rate depends on the sum of levels.
|
||||
sScriptMgr->OnPlayerRewardKillRewarder(player, this, isDungeon, xpRate); // Personal rate is 100%.
|
||||
float xpRate = _group ? _groupRate * float(_GetPlayerLevel(player)) / _aliveSumLevel : /*Personal rate is 100%.*/ 1.0f; // Group rate depends on the sum of levels.
|
||||
sScriptMgr->OnPlayerRewardKillRewarder(player, this, isDungeon, xpRate); // Personal rate is 100%.
|
||||
|
||||
if (_xp)
|
||||
{
|
||||
@@ -264,6 +265,13 @@ void KillRewarder::_RewardGroup()
|
||||
}
|
||||
}
|
||||
|
||||
uint8 KillRewarder::_GetPlayerLevel(Player const* player)
|
||||
{
|
||||
uint8 level = player->GetLevel();
|
||||
sScriptMgr->OnPlayerBeforeGetLevelForXPGain(player, level);
|
||||
return level;
|
||||
}
|
||||
|
||||
void KillRewarder::Reward()
|
||||
{
|
||||
// 3. Reward killer (and group, if necessary).
|
||||
|
||||
@@ -43,12 +43,14 @@ private:
|
||||
void _RewardKillCredit(Player* player);
|
||||
void _RewardPlayer(Player* player, bool isDungeon);
|
||||
void _RewardGroup();
|
||||
uint8 _GetPlayerLevel(Player const* player);
|
||||
|
||||
Player* _killer;
|
||||
Unit* _victim;
|
||||
Group* _group;
|
||||
float _groupRate;
|
||||
Player* _maxNotGrayMember;
|
||||
uint8 _maxNotGrayMemberLevel;
|
||||
uint32 _count;
|
||||
uint32 _aliveSumLevel;
|
||||
uint32 _sumLevel;
|
||||
|
||||
@@ -2370,6 +2370,7 @@ void Player::GiveXP(uint32 xp, Unit* victim, float group_rate, bool isLFGReward)
|
||||
}
|
||||
|
||||
uint8 level = GetLevel();
|
||||
sScriptMgr->OnPlayerBeforeGetLevelForXPGain(this, level);
|
||||
|
||||
// Favored experience increase START
|
||||
uint32 zone = GetZoneId();
|
||||
@@ -5784,17 +5785,20 @@ void Player::CheckAreaExploreAndOutdoor()
|
||||
|
||||
if (areaEntry->area_level > 0)
|
||||
{
|
||||
if (GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
uint8 playerLevel = GetLevel();
|
||||
sScriptMgr->OnPlayerBeforeGetLevelForXPGain(this, playerLevel);
|
||||
|
||||
if (playerLevel >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
{
|
||||
SendExplorationExperience(areaId, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int32 diff = int32(GetLevel()) - areaEntry->area_level;
|
||||
int32 diff = int32(playerLevel) - areaEntry->area_level;
|
||||
uint32 XP = 0;
|
||||
if (diff < -5)
|
||||
{
|
||||
XP = uint32(sObjectMgr->GetBaseXP(GetLevel() + 5) * sWorld->getRate(RATE_XP_EXPLORE));
|
||||
XP = uint32(sObjectMgr->GetBaseXP(playerLevel + 5) * sWorld->getRate(RATE_XP_EXPLORE));
|
||||
}
|
||||
else if (diff > 5)
|
||||
{
|
||||
|
||||
@@ -1435,8 +1435,11 @@ bool Player::TakeQuestSourceItem(uint32 questId, bool msg)
|
||||
|
||||
uint32 Player::CalculateQuestRewardXP(Quest const* quest)
|
||||
{
|
||||
uint8 level = GetLevel();
|
||||
sScriptMgr->OnPlayerBeforeGetLevelForXPGain(this, level);
|
||||
|
||||
// apply world quest rate
|
||||
uint32 xp = uint32(quest->XPValue(GetLevel()) * GetQuestRate(quest->IsDFQuest()));
|
||||
uint32 xp = uint32(quest->XPValue(level) * GetQuestRate(quest->IsDFQuest()));
|
||||
|
||||
// handle SPELL_AURA_MOD_XP_QUEST_PCT auras
|
||||
xp *= GetTotalAuraMultiplier(SPELL_AURA_MOD_XP_QUEST_PCT);
|
||||
|
||||
@@ -26,6 +26,73 @@ constexpr double DEG_TO_RAD = PI / 180.0;
|
||||
// Helper: sin/cos in degrees
|
||||
inline double sind(double deg) { return std::sin(deg * DEG_TO_RAD); }
|
||||
|
||||
// mktime() rejects pre-1970 dates on MSVC; these helpers normalize without it.
|
||||
static bool IsLeapYear(int year)
|
||||
{
|
||||
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
|
||||
}
|
||||
|
||||
static int DaysInMonth(int year, int month)
|
||||
{
|
||||
static int const table[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
return (month == 2 && IsLeapYear(year)) ? 29 : table[month - 1];
|
||||
}
|
||||
|
||||
static void NormalizeDate(std::tm& date)
|
||||
{
|
||||
int year = date.tm_year + 1900;
|
||||
int month = date.tm_mon + 1;
|
||||
int day = date.tm_mday;
|
||||
|
||||
while (month > 12)
|
||||
{
|
||||
month -= 12;
|
||||
++year;
|
||||
}
|
||||
while (month < 1)
|
||||
{
|
||||
month += 12;
|
||||
--year;
|
||||
}
|
||||
while (day > DaysInMonth(year, month))
|
||||
{
|
||||
day -= DaysInMonth(year, month);
|
||||
++month;
|
||||
if (month > 12)
|
||||
{
|
||||
month = 1;
|
||||
++year;
|
||||
}
|
||||
}
|
||||
while (day < 1)
|
||||
{
|
||||
--month;
|
||||
if (month < 1)
|
||||
{
|
||||
month = 12;
|
||||
--year;
|
||||
}
|
||||
day += DaysInMonth(year, month);
|
||||
}
|
||||
|
||||
date.tm_year = year - 1900;
|
||||
date.tm_mon = month - 1;
|
||||
date.tm_mday = day;
|
||||
|
||||
// Zeller's congruence; remap 0=Sat to POSIX 0=Sun.
|
||||
int zy = year;
|
||||
int zm = month;
|
||||
if (zm < 3)
|
||||
{
|
||||
zm += 12;
|
||||
--zy;
|
||||
}
|
||||
int const K = zy % 100;
|
||||
int const J = zy / 100;
|
||||
int const h = (day + (13 * (zm + 1)) / 5 + K + K / 4 + J / 4 + 5 * J) % 7;
|
||||
date.tm_wday = (h + 6) % 7;
|
||||
}
|
||||
|
||||
// Static holiday rules configuration
|
||||
static const std::vector<HolidayRule> HolidayRules = {
|
||||
// Lunar Festival: Chinese New Year - 1 day (event starts day before CNY)
|
||||
@@ -104,7 +171,7 @@ std::tm HolidayDateCalculator::CalculateEasterSunday(int year)
|
||||
result.tm_year = year - 1900;
|
||||
result.tm_mon = month - 1;
|
||||
result.tm_mday = day;
|
||||
mktime(&result); // Normalize and fill in other fields
|
||||
NormalizeDate(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -116,7 +183,7 @@ std::tm HolidayDateCalculator::CalculateNthWeekday(int year, int month, Weekday
|
||||
date.tm_year = year - 1900;
|
||||
date.tm_mon = month - 1;
|
||||
date.tm_mday = 1;
|
||||
mktime(&date);
|
||||
NormalizeDate(date);
|
||||
|
||||
// Find first occurrence of the target weekday
|
||||
int const daysUntilWeekday = (static_cast<int>(weekday) - date.tm_wday + 7) % 7;
|
||||
@@ -125,7 +192,7 @@ std::tm HolidayDateCalculator::CalculateNthWeekday(int year, int month, Weekday
|
||||
// Move to nth occurrence
|
||||
date.tm_mday += (n - 1) * 7;
|
||||
|
||||
mktime(&date); // Normalize (handles month overflow)
|
||||
NormalizeDate(date);
|
||||
return date;
|
||||
}
|
||||
|
||||
@@ -136,13 +203,13 @@ std::tm HolidayDateCalculator::CalculateWeekdayOnOrAfter(int year, int month, in
|
||||
date.tm_year = year - 1900;
|
||||
date.tm_mon = month - 1;
|
||||
date.tm_mday = day;
|
||||
mktime(&date);
|
||||
NormalizeDate(date);
|
||||
|
||||
// Find days until the target weekday (0 if already on that day)
|
||||
int const daysUntilWeekday = (static_cast<int>(weekday) - date.tm_wday + 7) % 7;
|
||||
date.tm_mday += daysUntilWeekday;
|
||||
|
||||
mktime(&date); // Normalize
|
||||
NormalizeDate(date);
|
||||
return date;
|
||||
}
|
||||
|
||||
@@ -288,7 +355,7 @@ std::tm HolidayDateCalculator::CalculateLunarNewYear(int year)
|
||||
result.tm_year = cnyYear - 1900;
|
||||
result.tm_mon = cnyMonth - 1;
|
||||
result.tm_mday = cnyDay;
|
||||
mktime(&result);
|
||||
NormalizeDate(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -298,7 +365,7 @@ std::tm HolidayDateCalculator::CalculateLunarNewYear(int year)
|
||||
fallback.tm_year = year - 1900;
|
||||
fallback.tm_mon = 0; // January
|
||||
fallback.tm_mday = 25;
|
||||
mktime(&fallback);
|
||||
NormalizeDate(fallback);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
@@ -354,7 +421,7 @@ std::tm HolidayDateCalculator::CalculateAutumnEquinox(int year)
|
||||
result.tm_year = eqYear - 1900;
|
||||
result.tm_mon = eqMonth - 1;
|
||||
result.tm_mday = eqDay;
|
||||
mktime(&result);
|
||||
NormalizeDate(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -408,7 +475,7 @@ std::tm HolidayDateCalculator::CalculateWinterSolstice(int year)
|
||||
result.tm_year = solYear - 1900;
|
||||
result.tm_mon = solMonth - 1;
|
||||
result.tm_mday = solDay;
|
||||
mktime(&result);
|
||||
NormalizeDate(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -423,7 +490,7 @@ std::tm HolidayDateCalculator::CalculateHolidayDate(const HolidayRule& rule, int
|
||||
result.tm_year = year - 1900;
|
||||
result.tm_mon = rule.month - 1;
|
||||
result.tm_mday = rule.day;
|
||||
mktime(&result);
|
||||
NormalizeDate(result);
|
||||
break;
|
||||
}
|
||||
case HolidayCalculationType::NTH_WEEKDAY:
|
||||
@@ -432,7 +499,7 @@ std::tm HolidayDateCalculator::CalculateHolidayDate(const HolidayRule& rule, int
|
||||
if (rule.offset != 0)
|
||||
{
|
||||
result.tm_mday += rule.offset;
|
||||
mktime(&result); // Normalize
|
||||
NormalizeDate(result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -440,7 +507,7 @@ std::tm HolidayDateCalculator::CalculateHolidayDate(const HolidayRule& rule, int
|
||||
{
|
||||
result = CalculateEasterSunday(year);
|
||||
result.tm_mday += rule.offset;
|
||||
mktime(&result); // Normalize
|
||||
NormalizeDate(result);
|
||||
break;
|
||||
}
|
||||
case HolidayCalculationType::LUNAR_NEW_YEAR:
|
||||
@@ -449,7 +516,7 @@ std::tm HolidayDateCalculator::CalculateHolidayDate(const HolidayRule& rule, int
|
||||
if (rule.offset != 0)
|
||||
{
|
||||
result.tm_mday += rule.offset;
|
||||
mktime(&result); // Normalize
|
||||
NormalizeDate(result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -459,7 +526,7 @@ std::tm HolidayDateCalculator::CalculateHolidayDate(const HolidayRule& rule, int
|
||||
if (rule.offset != 0)
|
||||
{
|
||||
result.tm_mday += rule.offset;
|
||||
mktime(&result); // Normalize
|
||||
NormalizeDate(result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -469,7 +536,7 @@ std::tm HolidayDateCalculator::CalculateHolidayDate(const HolidayRule& rule, int
|
||||
if (rule.offset != 0)
|
||||
{
|
||||
result.tm_mday += rule.offset;
|
||||
mktime(&result); // Normalize
|
||||
NormalizeDate(result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -479,7 +546,7 @@ std::tm HolidayDateCalculator::CalculateHolidayDate(const HolidayRule& rule, int
|
||||
if (rule.offset != 0)
|
||||
{
|
||||
result.tm_mday += rule.offset;
|
||||
mktime(&result); // Normalize
|
||||
NormalizeDate(result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -571,7 +638,7 @@ std::vector<uint32_t> HolidayDateCalculator::GetDarkmoonFaireDates(int locationO
|
||||
if (dayOffset != 0)
|
||||
{
|
||||
date.tm_mday += dayOffset;
|
||||
mktime(&date); // Normalize
|
||||
NormalizeDate(date);
|
||||
}
|
||||
dates.push_back(PackDate(date));
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "ObjectMgr.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
@@ -188,10 +189,13 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData*
|
||||
if (quest)
|
||||
{
|
||||
uint8 playerLevel = GetPlayer() ? GetPlayer()->GetLevel() : 0;
|
||||
uint8 playerLevelForXP = playerLevel;
|
||||
sScriptMgr->OnPlayerBeforeGetLevelForXPGain(GetPlayer(), playerLevelForXP);
|
||||
|
||||
data << uint8(done);
|
||||
data << uint32(quest->GetRewOrReqMoney(playerLevel));
|
||||
if (!GetPlayer()->IsMaxLevel())
|
||||
data << uint32(quest->XPValue(playerLevel));
|
||||
if (playerLevelForXP < GetPlayer()->GetUInt32Value(PLAYER_FIELD_MAX_LEVEL))
|
||||
data << uint32(quest->XPValue(playerLevelForXP));
|
||||
else
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
@@ -479,6 +483,8 @@ void WorldSession::SendLfgPlayerReward(lfg::LfgPlayerRewardData const& rewardDat
|
||||
uint8 itemNum = rewardData.quest->GetRewItemsCount();
|
||||
|
||||
uint8 playerLevel = GetPlayer() ? GetPlayer()->GetLevel() : 0;
|
||||
uint8 playerLevelForXP = playerLevel;
|
||||
sScriptMgr->OnPlayerBeforeGetLevelForXPGain(GetPlayer(), playerLevelForXP);
|
||||
|
||||
WorldPacket data(SMSG_LFG_PLAYER_REWARD, 4 + 4 + 1 + 4 + 4 + 4 + 4 + 4 + 1 + itemNum * (4 + 4 + 4));
|
||||
data << uint32(rewardData.rdungeonEntry); // Random Dungeon Finished
|
||||
@@ -486,7 +492,7 @@ void WorldSession::SendLfgPlayerReward(lfg::LfgPlayerRewardData const& rewardDat
|
||||
data << uint8(rewardData.done);
|
||||
data << uint32(1);
|
||||
data << uint32(rewardData.quest->GetRewOrReqMoney(playerLevel));
|
||||
data << uint32(rewardData.quest->XPValue(playerLevel));
|
||||
data << uint32(rewardData.quest->XPValue(playerLevelForXP));
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint8(itemNum);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "Creature.h"
|
||||
#include "Log.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "World.h"
|
||||
|
||||
uint32 Acore::XP::BaseGain(uint8 pl_level, uint8 mob_level, ContentLevels content)
|
||||
@@ -79,7 +80,9 @@ uint32 Acore::XP::Gain(Player* player, Unit* unit, bool isBattleGround /*= false
|
||||
{
|
||||
float xpMod = 1.0f;
|
||||
|
||||
gain = BaseGain(player->GetLevel(), unit->GetLevel(), GetContentLevelsForMapAndZone(unit->GetMapId(), unit->GetZoneId()));
|
||||
uint8 playerLevel = player->GetLevel();
|
||||
sScriptMgr->OnPlayerBeforeGetLevelForXPGain(player, playerLevel);
|
||||
gain = BaseGain(playerLevel, unit->GetLevel(), GetContentLevelsForMapAndZone(unit->GetMapId(), unit->GetZoneId()));
|
||||
|
||||
if (gain && creature)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
#include "PlayerScript.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptMgrMacros.h"
|
||||
#include "World.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
void ScriptMgr::OnPlayerBeforeDurabilityRepair(Player* player, ObjectGuid npcGUID, ObjectGuid itemGUID, float& discountMod, uint8 guildBank)
|
||||
{
|
||||
@@ -936,6 +939,12 @@ void ScriptMgr::OnPlayerLearnTaxiNode(Player const* player, uint32 nodeId)
|
||||
CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_LEARN_TAXI_NODE, script->OnPlayerLearnTaxiNode(player, nodeId));
|
||||
}
|
||||
|
||||
void ScriptMgr::OnPlayerBeforeGetLevelForXPGain(Player const* player, uint8& level)
|
||||
{
|
||||
CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_BEFORE_GET_LEVEL_FOR_XP_GAIN, script->OnPlayerBeforeGetLevelForXPGain(player, level));
|
||||
level = std::clamp(level, uint8(1), uint8(sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)));
|
||||
}
|
||||
|
||||
PlayerScript::PlayerScript(const char* name, std::vector<uint16> enabledHooks)
|
||||
: ScriptObject(name, PLAYERHOOK_END)
|
||||
{
|
||||
|
||||
@@ -217,6 +217,7 @@ enum PlayerHook
|
||||
PLAYERHOOK_ON_GIVE_REPUTATION,
|
||||
PLAYERHOOK_ON_GET_REPUTATION_PRICE_DISCOUNT,
|
||||
PLAYERHOOK_ON_LEARN_TAXI_NODE,
|
||||
PLAYERHOOK_ON_BEFORE_GET_LEVEL_FOR_XP_GAIN,
|
||||
PLAYERHOOK_END
|
||||
};
|
||||
|
||||
@@ -836,6 +837,14 @@ public:
|
||||
* @param nodeId The id of the learned taxi node
|
||||
*/
|
||||
virtual void OnPlayerLearnTaxiNode(Player const* /*player*/, uint32 /*nodeId*/) {}
|
||||
|
||||
/**
|
||||
* @brief This hook is called when XP is calculated for the player, and is used to modify the player level used in the XP formulas.
|
||||
*
|
||||
* @param player Contains information about the Player
|
||||
* @param level The level that should be used for XP gain calculations
|
||||
*/
|
||||
virtual void OnPlayerBeforeGetLevelForXPGain(Player const* /*player*/, uint8& /*level*/) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ServerScript.h"
|
||||
#include "IoContext.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptMgrMacros.h"
|
||||
#include "ServerScript.h"
|
||||
|
||||
void ScriptMgr::OnNetworkStart()
|
||||
void ScriptMgr::OnNetworkStart(Acore::Asio::IoContext& ioContext)
|
||||
{
|
||||
CALL_ENABLED_HOOKS(ServerScript, SERVERHOOK_ON_NETWORK_START, script->OnNetworkStart());
|
||||
CALL_ENABLED_HOOKS(ServerScript, SERVERHOOK_ON_NETWORK_START, script->OnNetworkStart(ioContext));
|
||||
}
|
||||
|
||||
void ScriptMgr::OnNetworkStop()
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#ifndef SCRIPT_OBJECT_SERVER_SCRIPT_H_
|
||||
#define SCRIPT_OBJECT_SERVER_SCRIPT_H_
|
||||
|
||||
#include "IoContext.h"
|
||||
#include "ScriptObject.h"
|
||||
#include <vector>
|
||||
#include <memory> // NOTE: this import is NEEDED (even though some IDEs report it as unused)
|
||||
@@ -41,6 +42,7 @@ protected:
|
||||
public:
|
||||
// Called when reactive socket I/O is started (WorldSocketMgr).
|
||||
virtual void OnNetworkStart() { }
|
||||
virtual void OnNetworkStart(Acore::Asio::IoContext& /*ioContext*/) { OnNetworkStart(); }
|
||||
|
||||
// Called when reactive I/O is stopped.
|
||||
virtual void OnNetworkStop() { }
|
||||
|
||||
@@ -173,7 +173,7 @@ public: /* SpellScriptLoader */
|
||||
void CreateSpellScriptLoaders(uint32 spellId, std::vector<std::pair<SpellScriptLoader*, std::multimap<uint32, uint32>::iterator>>& scriptVector);
|
||||
|
||||
public: /* ServerScript */
|
||||
void OnNetworkStart();
|
||||
void OnNetworkStart(Acore::Asio::IoContext& ioContext);
|
||||
void OnNetworkStop();
|
||||
void OnSocketOpen(std::shared_ptr<WorldSocket> const& socket);
|
||||
void OnSocketClose(std::shared_ptr<WorldSocket> const& socket);
|
||||
@@ -488,6 +488,7 @@ public: /* PlayerScript */
|
||||
void OnPlayerGetReputationPriceDiscount(Player const* player, Creature const* creature, float& discount);
|
||||
void OnPlayerGetReputationPriceDiscount(Player const* player, FactionTemplateEntry const* factionTemplate, float& discount);
|
||||
void OnPlayerLearnTaxiNode(Player const* player, uint32 nodeId);
|
||||
void OnPlayerBeforeGetLevelForXPGain(Player const* player, uint8& level);
|
||||
|
||||
// Anti cheat
|
||||
void AnticheatSetCanFlybyServer(Player* player, bool apply);
|
||||
|
||||
@@ -70,7 +70,7 @@ bool WorldSocketMgr::StartWorldNetwork(Acore::Asio::IoContext& ioContext, std::s
|
||||
|
||||
_acceptor->AsyncAcceptWithCallback<&WorldSocketMgr::OnSocketAccept>();
|
||||
|
||||
sScriptMgr->OnNetworkStart();
|
||||
sScriptMgr->OnNetworkStart(ioContext);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -5184,6 +5184,12 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->InterruptFlags &= ~SPELL_INTERRUPT_FLAG_INTERRUPT;
|
||||
});
|
||||
|
||||
// Twilight Torment
|
||||
ApplySpellFix({ 57935, 58835 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->ProcCharges = 0;
|
||||
});
|
||||
|
||||
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
|
||||
{
|
||||
SpellInfo* spellInfo = mSpellInfoMap[i];
|
||||
|
||||
@@ -129,6 +129,13 @@ struct boss_bjarngrim : public npc_escortAI
|
||||
AddWaypoint(7, 1262.0f, -26.9f, 33.5f, 0);
|
||||
}
|
||||
|
||||
void JustRespawned() override
|
||||
{
|
||||
npc_escortAI::JustRespawned();
|
||||
me->SetWalk(true);
|
||||
Start(true, ObjectGuid::Empty, nullptr, false, true);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
|
||||
@@ -457,113 +457,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum Aledis
|
||||
{
|
||||
SAY_CHALLENGE = 0,
|
||||
SAY_DEFEATED = 1,
|
||||
EVENT_TALK = 1,
|
||||
EVENT_ATTACK = 2,
|
||||
EVENT_EVADE = 3,
|
||||
EVENT_FIREBALL = 4,
|
||||
EVENT_FROSTNOVA = 5,
|
||||
SPELL_FIREBALL = 20823,
|
||||
SPELL_FROSTNOVA = 11831,
|
||||
};
|
||||
|
||||
struct npc_magister_aledis : public ScriptedAI
|
||||
{
|
||||
npc_magister_aledis(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void StartFight(Player* player)
|
||||
{
|
||||
me->Dismount();
|
||||
me->SetFacingToObject(player);
|
||||
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
|
||||
_playerGUID = player->GetGUID();
|
||||
_events.ScheduleEvent(EVENT_TALK, 2s);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->RestoreFaction();
|
||||
me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER);
|
||||
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
|
||||
me->SetImmuneToPC(true);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*spellInfo = nullptr*/) override
|
||||
{
|
||||
if (damage > me->GetHealth() || me->HealthBelowPctDamaged(20, damage))
|
||||
{
|
||||
damage = 0;
|
||||
|
||||
_events.Reset();
|
||||
me->RestoreFaction();
|
||||
me->RemoveAllAuras();
|
||||
me->GetThreatMgr().ClearAllThreat();
|
||||
me->CombatStop(true);
|
||||
me->SetNpcFlag(UNIT_NPC_FLAG_QUESTGIVER);
|
||||
me->SetImmuneToPC(true);
|
||||
Talk(SAY_DEFEATED);
|
||||
|
||||
_events.ScheduleEvent(EVENT_EVADE, 1min);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
_events.Update(diff);
|
||||
|
||||
while (uint32 eventId = _events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_TALK:
|
||||
Talk(SAY_CHALLENGE);
|
||||
_events.ScheduleEvent(EVENT_ATTACK, 2s);
|
||||
break;
|
||||
case EVENT_ATTACK:
|
||||
me->SetImmuneToPC(false);
|
||||
me->SetFaction(FACTION_MONSTER);
|
||||
if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID))
|
||||
{
|
||||
AttackStart(player);
|
||||
}
|
||||
_events.ScheduleEvent(EVENT_FIREBALL, 1ms);
|
||||
_events.ScheduleEvent(EVENT_FROSTNOVA, 5s);
|
||||
break;
|
||||
case EVENT_FIREBALL:
|
||||
DoCast(SPELL_FIREBALL);
|
||||
_events.ScheduleEvent(EVENT_FIREBALL, 10s);
|
||||
break;
|
||||
case EVENT_FROSTNOVA:
|
||||
DoCastAOE(SPELL_FROSTNOVA);
|
||||
_events.ScheduleEvent(EVENT_FROSTNOVA, 20s);
|
||||
break;
|
||||
case EVENT_EVADE:
|
||||
EnterEvadeMode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (UpdateVictim())
|
||||
{
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
}
|
||||
|
||||
void sGossipSelect(Player* player, uint32 /*sender*/, uint32 /*action*/) override
|
||||
{
|
||||
CloseGossipMenuFor(player);
|
||||
me->StopMoving();
|
||||
StartFight(player);
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap _events;
|
||||
ObjectGuid _playerGUID;
|
||||
};
|
||||
|
||||
enum Beacon
|
||||
{
|
||||
NPC_STONESCHYE_WHELP = 16927,
|
||||
@@ -645,6 +538,5 @@ void AddSC_hellfire_peninsula()
|
||||
new npc_fel_guard_hound();
|
||||
new go_beacon();
|
||||
|
||||
RegisterCreatureAI(npc_magister_aledis);
|
||||
RegisterGameObjectAI(go_magtheridons_head);
|
||||
}
|
||||
|
||||
@@ -329,6 +329,12 @@ struct npc_training_dummy : NullCreatureAI
|
||||
return;
|
||||
|
||||
_combatTimer[attacker->GetGUID()] = 5s;
|
||||
|
||||
// Pet attacks engage the owner via propagation without firing
|
||||
// JustEnteredCombat here, so track the owner's timer too.
|
||||
if (Unit* owner = attacker->GetCharmerOrOwner())
|
||||
if (me->GetCombatManager().IsInCombatWith(owner))
|
||||
_combatTimer[owner->GetGUID()] = 5s;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
|
||||
Reference in New Issue
Block a user