mirror of
https://github.com/araxiaonline/mod-mythic-plus.git
synced 2026-06-13 03:02:24 -04:00
286 lines
9.8 KiB
C++
286 lines
9.8 KiB
C++
#include "MpLogger.h"
|
|
#include "MpDataStore.h"
|
|
#include "MpScheduler.h"
|
|
#include "MythicPlus.h"
|
|
#include "Player.h"
|
|
#include "Group.h"
|
|
#include "ScriptMgr.h"
|
|
#include "TaskScheduler.h"
|
|
#include "AdvancementMgr.h"
|
|
#include "Formulas.h"
|
|
|
|
class MythicPlus_PlayerScript : public PlayerScript
|
|
{
|
|
public:
|
|
MythicPlus_PlayerScript() : PlayerScript("MythicPlus_PlayerScript") {}
|
|
|
|
/**
|
|
* Mythic+ special actions when a player dies:
|
|
* - Track the death for the group
|
|
* - Update the player death stats
|
|
* - Determine whether or not the Group failed the instance due to death count setting.
|
|
*/
|
|
|
|
void OnPlayerKilledByCreature(Creature* killer, Player* player) override
|
|
{
|
|
Map* map = player->GetMap();
|
|
if(!sMythicPlus->IsMapEligible(map)) {
|
|
return;
|
|
}
|
|
|
|
if (!player) {
|
|
return;
|
|
}
|
|
|
|
Group* group = player->GetGroup();
|
|
if(!group) {
|
|
MpLogger::warn("Missing group data for player {}", player->GetName());
|
|
return;
|
|
}
|
|
|
|
MpGroupData *data = sMpDataStore->GetGroupData(player->GetGroup());
|
|
if (!data) {
|
|
MpLogger::warn("Missing group data for player {}", player->GetName());
|
|
return;
|
|
}
|
|
|
|
MpPlayerData *playerData = sMpDataStore->GetPlayerData(player->GetGUID());
|
|
if (!playerData) {
|
|
MpLogger::warn("Missing player data for player {}", player->GetName());
|
|
return;
|
|
}
|
|
|
|
playerData->AddDeath(map->GetId(), map->GetInstanceId());
|
|
|
|
if(killer) {
|
|
sMpDataStore->DBAddPlayerDeath(player, killer, data->difficulty);
|
|
} else {
|
|
sMpDataStore->DBAddPlayerDeath(player);
|
|
}
|
|
|
|
sMpDataStore->DBAddGroupDeath(group, player->GetMapId(), player->GetInstanceId(), data->difficulty);
|
|
|
|
uint32 totalDeaths = data->GetDeaths(player->GetMapId(), player->GetInstanceId());
|
|
MpLogger::info("Total Deaths: {}", totalDeaths);
|
|
if(totalDeaths > 1) {
|
|
MpLogger::debug(" :::: Player Deaths for Group too high! ::::::");
|
|
|
|
TaskScheduler& wScheduler = sMpScheduler->GetWorldScheduler();
|
|
wScheduler.Schedule(10s, MP_WORLD_TASK_GROUP, [player, map](TaskContext /*ctx*/) {
|
|
Group* group = player->GetGroup();
|
|
if(!group) {
|
|
return;
|
|
}
|
|
|
|
MythicPlus::GroupReset(group, map);
|
|
});
|
|
}
|
|
// if(totalDeaths > 1) {
|
|
// Map* map = player->GetMap();
|
|
// if(!map) {
|
|
// return;
|
|
// }
|
|
// Group* group = player->GetGroup();
|
|
// if(!group) {
|
|
// MpLogger::warn("Player {} is not in a group.", player->GetName());
|
|
// return;
|
|
// }
|
|
|
|
// // map->RemoveAllPlayers();
|
|
// MpLogger::info("Starting scheduled failure notification");
|
|
// // auto testlambda = [](TaskContext ctx) { return; };
|
|
// sMpScheduler->ScheduleWorldTask(1s, [](TaskContext ctx) {
|
|
// MpLogger::info("<<<<<<<<<<< Player Death Scheduler fire >>>>>>>>>>>>>");
|
|
// });
|
|
|
|
// sMpScheduler->GetWorldScheduler().Schedule(1s, [playerName = player->GetName()](TaskContext ctx) {
|
|
// MpLogger::info("<<<<<<<<<<< Player Death Scheduler fire {} >>>>>>>>>>>>>", playerName);
|
|
// return;
|
|
// });
|
|
// std::vector<Player*> players = GetGroupMembers(player);
|
|
// MpLogger::info("Failed mythic+ instance run notification fired. ");
|
|
// WorldPacket data;
|
|
|
|
// for(Player* player : players)
|
|
// {
|
|
// MpLogger::info("Seding notification of failure to player: {}", player->GetName());
|
|
// player->GetSession()->SendShowBank(player->GetGUID());
|
|
// // player->GetSession()->SendNotification("Your group has died too many time to continue.");
|
|
// // ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID_BOSS_EMOTE, LANG_UNIVERSAL, nullptr, player, message);
|
|
// // player->GetSession()->SendPacket(&data);
|
|
// }
|
|
}
|
|
|
|
void OnBeforeLootMoney(Player* player, Loot* loot) override
|
|
{
|
|
if (!loot->sourceWorldObjectGUID.IsCreature()) return;
|
|
|
|
Creature* creature = player->GetMap()->GetCreature(loot->sourceWorldObjectGUID);
|
|
if (!creature) return;
|
|
|
|
#ifdef NPC_BOT
|
|
if(creature->IsNPCBotOrPet()) {
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// Check if this is a Mythic+ scaled creature
|
|
MpCreatureData* creatureData = sMpDataStore->GetCreatureData(creature->GetGUID());
|
|
if (!creatureData || !creatureData->IsScaled()) return;
|
|
|
|
// Different gold ranges based on creature rank
|
|
uint32 bossMinGold = 10000;
|
|
uint32 bossMaxGold = 13500;
|
|
|
|
uint32 minGold, maxGold;
|
|
|
|
// Determine gold range based on creature rank
|
|
if (creature->isWorldBoss() || creature->IsDungeonBoss())
|
|
{
|
|
// Boss: full range
|
|
minGold = bossMinGold;
|
|
maxGold = bossMaxGold;
|
|
}
|
|
else if (creature->GetCreatureTemplate()->rank == CREATURE_ELITE_RARE ||
|
|
creature->GetCreatureTemplate()->rank == CREATURE_ELITE_ELITE)
|
|
{
|
|
// Elite: 70% of boss range
|
|
minGold = uint32(bossMinGold * 0.7f);
|
|
maxGold = uint32(bossMaxGold * 0.7f);
|
|
}
|
|
else
|
|
{
|
|
// Normal: 40% of boss range
|
|
minGold = uint32(bossMinGold * 0.4f);
|
|
maxGold = uint32(bossMaxGold * 0.4f);
|
|
}
|
|
|
|
// Generate random gold amount in appropriate range
|
|
uint32 newGold = urand(minGold, maxGold);
|
|
|
|
// Apply server money rate
|
|
newGold = uint32(newGold * sWorld->getRate(RATE_DROP_MONEY));
|
|
|
|
loot->gold = newGold;
|
|
}
|
|
|
|
void OnGiveXP(Player* player, uint32& amount, Unit* victim, uint8 xpSource) override
|
|
{
|
|
if (xpSource != XPSOURCE_KILL || !victim) return;
|
|
|
|
Creature* creature = victim->ToCreature();
|
|
if (!creature) return;
|
|
|
|
#ifdef NPC_BOT
|
|
if(creature->IsNPCBotOrPet()) {
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// Check if this is a Mythic+ scaled creature
|
|
MpCreatureData* creatureData = sMpDataStore->GetCreatureData(creature->GetGUID());
|
|
if (!creatureData || !creatureData->IsScaled()) return;
|
|
|
|
// Recalculate XP using scaled level instead of original level
|
|
uint32 newBaseXP = Acore::XP::BaseGain(
|
|
player->GetLevel(),
|
|
creature->GetLevel(), // This is now the scaled level
|
|
GetContentLevelsForMapAndZone(creature->GetMapId(), creature->GetZoneId())
|
|
);
|
|
|
|
// Apply same modifiers as original calculation
|
|
float xpMod = 1.0f;
|
|
if (creature->isElite()) {
|
|
xpMod *= creature->GetMap()->IsDungeon() ? 2.75f : 2.0f;
|
|
}
|
|
xpMod *= creature->GetCreatureTemplate()->ModExperience;
|
|
|
|
amount = uint32(newBaseXP * xpMod * 1.5f); // flat bonus modifier for mythic dungeons
|
|
}
|
|
void OnLogin(Player* player) override
|
|
{
|
|
MpLogger::info("Player {} logged in", player->GetName());
|
|
|
|
// Load the player advancement data for the player when they login
|
|
sAdvancementMgr->LoadPlayerAdvancements(player);
|
|
|
|
// Cast all unique advancement spells
|
|
for(uint32 i = 1; i <= 10; ++i) {
|
|
uint32 spellId = 80000000 + i;
|
|
MpLogger::info("Casting spell {} to player {}", spellId, player->GetName());
|
|
player->AddAura(spellId, player);
|
|
}
|
|
}
|
|
|
|
// When a player is bound to an instance need to make sure they are saved in the data soure to retrieve later.
|
|
void OnBindToInstance(Player* player, Difficulty /*difficulty*/, uint32 mapId, bool /*permanent*/) override
|
|
{
|
|
if(!player) {
|
|
return;
|
|
}
|
|
|
|
Group* group = player->GetGroup();
|
|
|
|
// If they are not in a group do nothing.
|
|
if(!group) {
|
|
return;
|
|
}
|
|
|
|
MpGroupData* data = sMpDataStore->GetGroupData(group);
|
|
|
|
// If there is not any mythic+ data set for this group do nothing.
|
|
if(!data) {
|
|
return;
|
|
}
|
|
|
|
Map* map = player->GetMap();
|
|
if(!map) {
|
|
MpLogger::warn("Player {} is not in a map", player->GetName());
|
|
return;
|
|
}
|
|
|
|
// get the player data or set it up
|
|
MpPlayerData* playerData = sMpDataStore->GetPlayerData(player->GetGUID());
|
|
if(!playerData) {
|
|
playerData = new MpPlayerData(player, data->difficulty, group->GetGUID().GetCounter());
|
|
sMpDataStore->AddPlayerData(player->GetGUID(), playerData);
|
|
}
|
|
|
|
// Add this players data to the group data
|
|
data->AddPlayerData(playerData);
|
|
|
|
auto mapKey = sMpDataStore->GetInstanceDataKey(mapId, player->GetInstanceId());
|
|
playerData->instanceData.emplace(mapKey, MpPlayerInstanceData{
|
|
.deaths = 0,
|
|
});
|
|
|
|
sMpDataStore->DBUpdatePlayerInstanceData(player->GetGUID(), data->difficulty, map->GetId(), map->GetInstanceId());
|
|
sMpDataStore->DBUpdateGroupData(group->GetGUID(), data->difficulty, map->GetId(), map->GetInstanceId(), 0);
|
|
}
|
|
|
|
std::vector<Player*> GetGroupMembers(Player* currentPlayer)
|
|
{
|
|
std::vector<Player*> groupPlayers;
|
|
|
|
Group* group = currentPlayer->GetGroup();
|
|
if (!group)
|
|
{
|
|
MpLogger::warn("Player is not in a group.");
|
|
return groupPlayers;
|
|
}
|
|
|
|
group->DoForAllMembers([&](Player* member) {
|
|
groupPlayers.push_back(member);
|
|
});
|
|
|
|
return groupPlayers;
|
|
}
|
|
|
|
};
|
|
|
|
void Add_MP_PlayerScripts()
|
|
{
|
|
MpLogger::debug("Add_MP_PlayerScripts()");
|
|
new MythicPlus_PlayerScript();
|
|
}
|