50 plus cmangos updates implemented (to c12832)

Implemented over 50 updates from the cmangos Cata repo, up to and
including c12832 Improve random movement

The core will now work with the creature_template update that was
applied to the database yesterday.
This commit is contained in:
Charles A Edwards 2016-08-16 11:58:07 +01:00 committed by Antz
parent 12f8fbf37d
commit e4d1bdfc74
80 changed files with 3164 additions and 2965 deletions

File diff suppressed because it is too large Load diff

View file

@ -53,6 +53,9 @@ namespace MaNGOS
{ {
char const* text = sObjectMgr.GetMangosString(i_textId, loc_idx); char const* text = sObjectMgr.GetMangosString(i_textId, loc_idx);
ObjectGuid sourceGuid = i_source ? i_source->GetObjectGuid() : ObjectGuid();
std::string sourceName = i_source ? i_source->GetName() : "";
if (i_args) if (i_args)
{ {
// we need copy va_list before use or original va_list will corrupted // we need copy va_list before use or original va_list will corrupted
@ -63,26 +66,12 @@ namespace MaNGOS
vsnprintf(str, 2048, text, ap); vsnprintf(str, 2048, text, ap);
va_end(ap); va_end(ap);
do_helper(data, &str[0]); ChatHandler::BuildChatPacket(data, i_msgtype, &str[0], LANG_UNIVERSAL, CHAT_TAG_NONE, sourceGuid, sourceName.c_str());
} }
else else
do_helper(data, text); ChatHandler::BuildChatPacket(data, i_msgtype, text, LANG_UNIVERSAL, CHAT_TAG_NONE, sourceGuid, sourceName.c_str(), sourceGuid, sourceName.c_str());
} }
private: private:
void do_helper(WorldPacket& data, char const* text)
{
ObjectGuid targetGuid = i_source ? i_source ->GetObjectGuid() : ObjectGuid();
data << uint8(i_msgtype);
data << uint32(LANG_UNIVERSAL);
data << ObjectGuid(targetGuid); // there 0 for BG messages
data << uint32(0); // can be chat msg group or something
data << ObjectGuid(targetGuid);
data << uint32(strlen(text) + 1);
data << text;
data << uint8(i_source ? i_source->GetChatTag() : uint8(CHAT_TAG_NONE));
}
ChatMsg i_msgtype; ChatMsg i_msgtype;
int32 i_textId; int32 i_textId;
Player const* i_source; Player const* i_source;
@ -92,7 +81,7 @@ namespace MaNGOS
class BattleGroundYellBuilder class BattleGroundYellBuilder
{ {
public: public:
BattleGroundYellBuilder(uint32 language, int32 textId, Creature const* source, va_list* args = NULL) BattleGroundYellBuilder(Language language, int32 textId, Creature const* source, va_list* args = nullptr)
: i_language(language), i_textId(textId), i_source(source), i_args(args) {} : i_language(language), i_textId(textId), i_source(source), i_args(args) {}
void operator()(WorldPacket& data, int32 loc_idx) void operator()(WorldPacket& data, int32 loc_idx)
{ {
@ -108,28 +97,13 @@ namespace MaNGOS
vsnprintf(str, 2048, text, ap); vsnprintf(str, 2048, text, ap);
va_end(ap); va_end(ap);
do_helper(data, &str[0]); ChatHandler::BuildChatPacket(data, CHAT_MSG_MONSTER_YELL, &str[0], i_language, CHAT_TAG_NONE, i_source->GetObjectGuid(), i_source->GetName());
} }
else else
do_helper(data, text); ChatHandler::BuildChatPacket(data, CHAT_MSG_MONSTER_YELL, text, i_language, CHAT_TAG_NONE, i_source->GetObjectGuid(), i_source->GetName());
} }
private: private:
void do_helper(WorldPacket& data, char const* text) Language i_language;
{
// copyied from BuildMonsterChat
data << uint8(CHAT_MSG_MONSTER_YELL);
data << uint32(i_language);
data << ObjectGuid(i_source->GetObjectGuid());
data << uint32(0); // 2.1.0
data << uint32(strlen(i_source->GetName()) + 1);
data << i_source->GetName();
data << ObjectGuid(); // Unit Target - isn't important for bgs
data << uint32(strlen(text) + 1);
data << text;
data << uint8(0); // ChatTag - for bgs allways 0?
}
uint32 i_language;
int32 i_textId; int32 i_textId;
Creature const* i_source; Creature const* i_source;
va_list* i_args; va_list* i_args;
@ -150,19 +124,16 @@ namespace MaNGOS
char str [2048]; char str [2048];
snprintf(str, 2048, text, arg1str, arg2str); snprintf(str, 2048, text, arg1str, arg2str);
ObjectGuid targetGuid = i_source ? i_source ->GetObjectGuid() : ObjectGuid(); ObjectGuid guid;
char const* pName = nullptr;
data << uint8(i_msgtype); if (i_source)
data << uint32(LANG_UNIVERSAL); {
data << ObjectGuid(targetGuid); // there 0 for BG messages guid = i_source->GetObjectGuid();
data << uint32(0); // can be chat msg group or something pName = i_source->GetName();
data << ObjectGuid(targetGuid); }
data << uint32(strlen(str) + 1); ChatHandler::BuildChatPacket(data, i_msgtype, str, LANG_UNIVERSAL, CHAT_TAG_NONE, ObjectGuid(), nullptr, guid, pName);
data << str;
data << uint8(i_source ? i_source->GetChatTag() : uint8(CHAT_TAG_NONE));
} }
private: private:
ChatMsg i_msgtype; ChatMsg i_msgtype;
int32 i_textId; int32 i_textId;
Player const* i_source; Player const* i_source;
@ -1589,7 +1560,7 @@ void BattleGround::SendYellToAll(int32 entry, uint32 language, ObjectGuid guid)
Creature* source = GetBgMap()->GetCreature(guid); Creature* source = GetBgMap()->GetCreature(guid);
if (!source) if (!source)
return; return;
MaNGOS::BattleGroundYellBuilder bg_builder(language, entry, source); MaNGOS::BattleGroundYellBuilder bg_builder(Language(language), entry, source);
MaNGOS::LocalizedPacketDo<MaNGOS::BattleGroundYellBuilder> bg_do(bg_builder); MaNGOS::LocalizedPacketDo<MaNGOS::BattleGroundYellBuilder> bg_do(bg_builder);
BroadcastWorker(bg_do); BroadcastWorker(bg_do);
} }

View file

@ -178,19 +178,19 @@ void BattleGroundEY::HandleGameObjectCreate(GameObject* go)
{ {
case GO_CAPTURE_POINT_BLOOD_ELF_TOWER: case GO_CAPTURE_POINT_BLOOD_ELF_TOWER:
m_towers[NODE_BLOOD_ELF_TOWER] = go->GetObjectGuid(); m_towers[NODE_BLOOD_ELF_TOWER] = go->GetObjectGuid();
go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE); go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE, false);
break; break;
case GO_CAPTURE_POINT_FEL_REAVER_RUINS: case GO_CAPTURE_POINT_FEL_REAVER_RUINS:
m_towers[NODE_FEL_REAVER_RUINS] = go->GetObjectGuid(); m_towers[NODE_FEL_REAVER_RUINS] = go->GetObjectGuid();
go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE); go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE, false);
break; break;
case GO_CAPTURE_POINT_MAGE_TOWER: case GO_CAPTURE_POINT_MAGE_TOWER:
m_towers[NODE_MAGE_TOWER] = go->GetObjectGuid(); m_towers[NODE_MAGE_TOWER] = go->GetObjectGuid();
go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE); go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE, false);
break; break;
case GO_CAPTURE_POINT_DRAENEI_RUINS: case GO_CAPTURE_POINT_DRAENEI_RUINS:
m_towers[NODE_DRAENEI_RUINS] = go->GetObjectGuid(); m_towers[NODE_DRAENEI_RUINS] = go->GetObjectGuid();
go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE); go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE, false);
break; break;
} }
} }

View file

@ -58,7 +58,7 @@ bool ChatHandler::HandleNpcSayCommand(char* args)
return false; return false;
} }
pCreature->MonsterSay(args, LANG_UNIVERSAL); pCreature->MonsterSay(args, LANG_UNIVERSAL, m_session->GetPlayer());
return true; return true;
} }
@ -76,7 +76,7 @@ bool ChatHandler::HandleNpcYellCommand(char* args)
return false; return false;
} }
pCreature->MonsterYell(args, LANG_UNIVERSAL); pCreature->MonsterYell(args, LANG_UNIVERSAL, m_session->GetPlayer());
return true; return true;
} }
@ -96,7 +96,7 @@ bool ChatHandler::HandleNpcTextEmoteCommand(char* args)
return false; return false;
} }
pCreature->MonsterTextEmote(args, NULL); pCreature->MonsterTextEmote(args, m_session->GetPlayer());
return true; return true;
} }
@ -909,9 +909,9 @@ bool ChatHandler::HandleModifyFactionCommand(char* args)
{ {
uint32 factionid = chr->getFaction(); uint32 factionid = chr->getFaction();
uint32 flag = chr->GetUInt32Value(UNIT_FIELD_FLAGS); uint32 flag = chr->GetUInt32Value(UNIT_FIELD_FLAGS);
uint32 npcflag = chr->GetUInt32Value(UNIT_NPC_FLAGS); uint32 NpcFlags = chr->GetUInt32Value(UNIT_NPC_FLAGS);
uint32 dyflag = chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS); uint32 dyflag = chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS);
PSendSysMessage(LANG_CURRENT_FACTION, chr->GetGUIDLow(), factionid, flag, npcflag, dyflag); PSendSysMessage(LANG_CURRENT_FACTION, chr->GetGUIDLow(), factionid, flag, NpcFlags, dyflag);
} }
return true; return true;
} }
@ -938,19 +938,19 @@ bool ChatHandler::HandleModifyFactionCommand(char* args)
if (!ExtractOptUInt32(&args, flag, chr->GetUInt32Value(UNIT_FIELD_FLAGS))) if (!ExtractOptUInt32(&args, flag, chr->GetUInt32Value(UNIT_FIELD_FLAGS)))
return false; return false;
uint32 npcflag; uint32 NpcFlags;
if (!ExtractOptUInt32(&args, npcflag, chr->GetUInt32Value(UNIT_NPC_FLAGS))) if (!ExtractOptUInt32(&args, NpcFlags, chr->GetUInt32Value(UNIT_NPC_FLAGS)))
return false; return false;
uint32 dyflag; uint32 dyflag;
if (!ExtractOptUInt32(&args, dyflag, chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS))) if (!ExtractOptUInt32(&args, dyflag, chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS)))
return false; return false;
PSendSysMessage(LANG_YOU_CHANGE_FACTION, chr->GetGUIDLow(), factionid, flag, npcflag, dyflag); PSendSysMessage(LANG_YOU_CHANGE_FACTION, chr->GetGUIDLow(), factionid, flag, NpcFlags, dyflag);
chr->setFaction(factionid); chr->setFaction(factionid);
chr->SetUInt32Value(UNIT_FIELD_FLAGS, flag); chr->SetUInt32Value(UNIT_FIELD_FLAGS, flag);
chr->SetUInt32Value(UNIT_NPC_FLAGS, npcflag); chr->SetUInt32Value(UNIT_NPC_FLAGS, NpcFlags);
chr->SetUInt32Value(UNIT_DYNAMIC_FLAGS, dyflag); chr->SetUInt32Value(UNIT_DYNAMIC_FLAGS, dyflag);
return true; return true;

View file

@ -1878,7 +1878,7 @@ bool ChatHandler::HandleNpcChangeLevelCommand(char* args)
return true; return true;
} }
// set npcflag of creature // set NpcFlags of creature
bool ChatHandler::HandleNpcFlagCommand(char* args) bool ChatHandler::HandleNpcFlagCommand(char* args)
{ {
if (!*args) if (!*args)
@ -1897,7 +1897,7 @@ bool ChatHandler::HandleNpcFlagCommand(char* args)
pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags); pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags);
WorldDatabase.PExecuteLog("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry()); WorldDatabase.PExecuteLog("UPDATE creature_template SET NpcFlags = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry());
SendSysMessage(LANG_VALUE_SAVED_REJOIN); SendSysMessage(LANG_VALUE_SAVED_REJOIN);

View file

@ -1137,6 +1137,14 @@ bool ChatHandler::HandleReloadMailLevelRewardCommand(char* /*args*/)
return true; return true;
} }
bool ChatHandler::HandleReloadCreaturesStatsCommand(char* /*args*/)
{
sLog.outString("Re-Loading stats data...");
sObjectMgr.LoadCreatureClassLvlStats();
SendGlobalSysMessage("DB table `creature_template_classlevelstats` reloaded.");
return true;
}
bool ChatHandler::HandleLoadScriptsCommand(char* args) bool ChatHandler::HandleLoadScriptsCommand(char* args)
{ {
if (!*args) if (!*args)
@ -2472,7 +2480,7 @@ bool ChatHandler::HandleLearnAllMyPetTalentsCommand(char* /*args*/)
return false; return false;
} }
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family); CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->Family);
if (!pet_family) if (!pet_family)
{ {
SendSysMessage(LANG_WRONG_PET_TYPE); SendSysMessage(LANG_WRONG_PET_TYPE);
@ -4338,7 +4346,7 @@ bool ChatHandler::HandleNpcInfoCommand(char* /*args*/)
} }
uint32 faction = target->getFaction(); uint32 faction = target->getFaction();
uint32 npcflags = target->GetUInt32Value(UNIT_NPC_FLAGS); uint32 NpcFlagss = target->GetUInt32Value(UNIT_NPC_FLAGS);
uint32 displayid = target->GetDisplayId(); uint32 displayid = target->GetDisplayId();
uint32 nativeid = target->GetNativeDisplayId(); uint32 nativeid = target->GetNativeDisplayId();
uint32 Entry = target->GetEntry(); uint32 Entry = target->GetEntry();
@ -4358,25 +4366,25 @@ bool ChatHandler::HandleNpcInfoCommand(char* /*args*/)
break; break;
if (diff < MAX_DIFFICULTY) if (diff < MAX_DIFFICULTY)
PSendSysMessage(LANG_NPCINFO_CHAR_DIFFICULTY, target->GetGuidStr().c_str(), faction, npcflags, PSendSysMessage(LANG_NPCINFO_CHAR_DIFFICULTY, target->GetGuidStr().c_str(), faction, NpcFlagss,
Entry, target->GetCreatureInfo()->Entry, diff, Entry, target->GetCreatureInfo()->Entry, diff,
displayid, nativeid); displayid, nativeid);
else else
PSendSysMessage(LANG_NPCINFO_CHAR, target->GetGuidStr().c_str(), faction, npcflags, Entry, displayid, nativeid); PSendSysMessage(LANG_NPCINFO_CHAR, target->GetGuidStr().c_str(), faction, NpcFlagss, Entry, displayid, nativeid);
PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel()); PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel());
PSendSysMessage(LANG_NPCINFO_HEALTH, target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth()); PSendSysMessage(LANG_NPCINFO_HEALTH, target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth());
PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS), target->GetUInt32Value(UNIT_DYNAMIC_FLAGS), target->getFaction()); PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS), target->GetUInt32Value(UNIT_DYNAMIC_FLAGS), target->getFaction());
PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(), curRespawnDelayStr.c_str()); PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(), curRespawnDelayStr.c_str());
PSendSysMessage(LANG_NPCINFO_LOOT, cInfo->lootid, cInfo->pickpocketLootId, cInfo->SkinLootId); PSendSysMessage(LANG_NPCINFO_LOOT, cInfo->LootId, cInfo->PickpocketLootId, cInfo->SkinningLootId);
PSendSysMessage(LANG_NPCINFO_DUNGEON_ID, target->GetInstanceId()); PSendSysMessage(LANG_NPCINFO_DUNGEON_ID, target->GetInstanceId());
PSendSysMessage(LANG_NPCINFO_POSITION, float(target->GetPositionX()), float(target->GetPositionY()), float(target->GetPositionZ())); PSendSysMessage(LANG_NPCINFO_POSITION, float(target->GetPositionX()), float(target->GetPositionY()), float(target->GetPositionZ()));
if ((npcflags & UNIT_NPC_FLAG_VENDOR)) if ((NpcFlagss & UNIT_NPC_FLAG_VENDOR))
{ {
SendSysMessage(LANG_NPCINFO_VENDOR); SendSysMessage(LANG_NPCINFO_VENDOR);
} }
if ((npcflags & UNIT_NPC_FLAG_TRAINER)) if ((NpcFlagss & UNIT_NPC_FLAG_TRAINER))
{ {
SendSysMessage(LANG_NPCINFO_TRAINER); SendSysMessage(LANG_NPCINFO_TRAINER);
} }

View file

@ -313,7 +313,7 @@ bool ChatHandler::HandleDebugSendChatMsgCommand(char* args)
return false; return false;
WorldPacket data; WorldPacket data;
ChatHandler::FillMessageData(&data, m_session, type, 0, "chan", m_session->GetPlayer()->GetObjectGuid(), msg, m_session->GetPlayer()); ChatHandler::BuildChatPacket(data, ChatMsg(type), msg, LANG_UNIVERSAL, CHAT_TAG_NONE, m_session->GetPlayer()->GetObjectGuid(), m_session->GetPlayerName());
m_session->SendPacket(&data); m_session->SendPacket(&data);
return true; return true;
} }

View file

@ -46,13 +46,42 @@ RandomMovementGenerator<Creature>::RandomMovementGenerator(const Creature& creat
template<> template<>
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature) void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
{
float destX = i_x;
float destY = i_y;
float destZ = i_z;
creature.addUnitState(UNIT_STAT_ROAMING_MOVE);
// check if new random position is assigned, GetReachableRandomPosition may fail
if (creature.GetMap()->GetReachableRandomPosition(&creature, destX, destY, destZ, i_radius))
{
Movement::MoveSplineInit init(creature);
init.MoveTo(destX, destY, destZ, true);
init.SetWalk(true);
init.Launch();
if (roll_chance_i(MOVEMENT_RANDOM_MMGEN_CHANCE_NO_BREAK))
i_nextMoveTime.Reset(50);
else
i_nextMoveTime.Reset(urand(3000, 10000)); // Keep a short wait time
}
else
i_nextMoveTime.Reset(50); // Retry later
return;
}
/*
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
{ {
const float angle = rand_norm_f() * (M_PI_F * 2.0f); const float angle = rand_norm_f() * (M_PI_F * 2.0f);
const float range = rand_norm_f() * i_radius; const float range = rand_norm_f() * i_radius;
float destX = i_x + range * cos(angle); float destX = i_x;
float destY = i_y + range * sin(angle); float destY = i_y;
float destZ = i_z + frand(-1, 1) * i_verticalZ; float destZ = i_z;
// float destX = i_x + range * cos(angle);
// float destY = i_y + range * sin(angle);
// float destZ = i_z + frand(-1, 1) * i_verticalZ;
creature.UpdateAllowedPositionZ(destX, destY, destZ); creature.UpdateAllowedPositionZ(destX, destY, destZ);
creature.addUnitState(UNIT_STAT_ROAMING_MOVE); creature.addUnitState(UNIT_STAT_ROAMING_MOVE);
@ -67,6 +96,7 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
else else
i_nextMoveTime.Reset(urand(500, 10000)); i_nextMoveTime.Reset(urand(500, 10000));
} }
*/
template<> template<>
void RandomMovementGenerator<Creature>::Initialize(Creature& creature) void RandomMovementGenerator<Creature>::Initialize(Creature& creature)

View file

@ -27,6 +27,9 @@
#include "MovementGenerator.h" #include "MovementGenerator.h"
// define chance for creature to not stop after reaching a waypoint
#define MOVEMENT_RANDOM_MMGEN_CHANCE_NO_BREAK 30
template<class T> template<class T>
class RandomMovementGenerator class RandomMovementGenerator
: public MovementGeneratorMedium< T, RandomMovementGenerator<T> > : public MovementGeneratorMedium< T, RandomMovementGenerator<T> >

View file

@ -142,6 +142,7 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature)
if (behavior->textid[0]) if (behavior->textid[0])
{ {
int32 textId = behavior->textid[0];
// Not only one text is set // Not only one text is set
if (behavior->textid[1]) if (behavior->textid[1])
{ {
@ -153,10 +154,13 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature)
break; break;
} }
creature.MonsterSay(behavior->textid[rand() % i], LANG_UNIVERSAL); textId = behavior->textid[urand(0, i - 1)];
} }
if (MangosStringLocale const* textData = sObjectMgr.GetMangosStringLocale(textId))
creature.MonsterText(textData, nullptr);
else else
creature.MonsterSay(behavior->textid[0], LANG_UNIVERSAL); sLog.outErrorDb("%s reached waypoint %u, attempted to do text %i, but required text-data could not be found", creature.GetGuidStr().c_str(), i_currentNode, textId);
} }
} }

View file

@ -846,9 +846,25 @@ void WorldSession::BuildListAuctionItems(std::vector<AuctionEntry*> const& aucti
if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax))) if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax)))
continue; continue;
if (usable != 0x00 && _player->CanUseItem(item) != EQUIP_ERR_OK) if (usable != 0x00)
{
if (_player->CanUseItem(item) != EQUIP_ERR_OK)
continue; continue;
if (proto->Class == ITEM_CLASS_RECIPE)
{
if (SpellEntry const* spell = sSpellStore.LookupEntry(proto->Spells[0].SpellId))
{
SpellEffectEntry const* spellEff = spell->GetSpellEffect(EFFECT_INDEX_0);
if (!spellEff)
continue;
if (_player->HasSpell(spellEff->EffectTriggerSpell))
continue;
}
}
}
std::string name = proto->Name1; std::string name = proto->Name1;
sObjectMgr.GetItemLocaleStrings(proto->ItemId, loc_idx, &name); sObjectMgr.GetItemLocaleStrings(proto->ItemId, loc_idx, &name);

View file

@ -165,7 +165,7 @@ Creature::Creature(CreatureSubtype subtype) : Unit(),
lootForPickPocketed(false), lootForBody(false), lootForSkin(false), lootForPickPocketed(false), lootForBody(false), lootForSkin(false),
m_groupLootTimer(0), m_groupLootId(0), m_groupLootTimer(0), m_groupLootId(0),
m_lootMoney(0), m_lootGroupRecipientId(0), m_lootMoney(0), m_lootGroupRecipientId(0),
m_corpseDecayTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(5.0f), m_corpseDecayTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_aggroDelay(0), m_respawnradius(5.0f),
m_subtype(subtype), m_defaultMovementType(IDLE_MOTION_TYPE), m_equipmentId(0), m_subtype(subtype), m_defaultMovementType(IDLE_MOTION_TYPE), m_equipmentId(0),
m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false),
m_regenHealth(true), m_AI_locked(false), m_IsDeadByDefault(false), m_regenHealth(true), m_AI_locked(false), m_IsDeadByDefault(false),
@ -310,7 +310,7 @@ bool Creature::InitEntry(uint32 Entry, CreatureData const* data /*=NULL*/, GameE
SetByteValue(UNIT_FIELD_BYTES_0, 0, 0); SetByteValue(UNIT_FIELD_BYTES_0, 0, 0);
// known valid are: CLASS_WARRIOR,CLASS_PALADIN,CLASS_ROGUE,CLASS_MAGE // known valid are: CLASS_WARRIOR,CLASS_PALADIN,CLASS_ROGUE,CLASS_MAGE
SetByteValue(UNIT_FIELD_BYTES_0, 1, uint8(cinfo->unit_class)); SetByteValue(UNIT_FIELD_BYTES_0, 1, uint8(cinfo->UnitClass));
uint32 display_id = ChooseDisplayId(GetCreatureInfo(), data, eventData); uint32 display_id = ChooseDisplayId(GetCreatureInfo(), data, eventData);
if (!display_id) // Cancel load if no display id if (!display_id) // Cancel load if no display id
@ -374,28 +374,26 @@ bool Creature::UpdateEntry(uint32 Entry, Team team, const CreatureData* data /*=
if (!InitEntry(Entry, data, eventData)) if (!InitEntry(Entry, data, eventData))
return false; return false;
m_regenHealth = GetCreatureInfo()->RegenHealth;
// creatures always have melee weapon ready if any // creatures always have melee weapon ready if any
SetSheath(SHEATH_STATE_MELEE); SetSheath(SHEATH_STATE_MELEE);
SelectLevel(GetCreatureInfo(), preserveHPAndPower ? GetHealthPercent() : 100.0f, 100.0f); SelectLevel(GetCreatureInfo(), preserveHPAndPower ? GetHealthPercent() : 100.0f);
if (team == HORDE) if (team == HORDE)
setFaction(GetCreatureInfo()->FactionHorde); setFaction(GetCreatureInfo()->FactionHorde);
else else
setFaction(GetCreatureInfo()->FactionAlliance); setFaction(GetCreatureInfo()->FactionAlliance);
SetUInt32Value(UNIT_NPC_FLAGS, GetCreatureInfo()->npcflag); SetUInt32Value(UNIT_NPC_FLAGS, GetCreatureInfo()->NpcFlags);
uint32 attackTimer = GetCreatureInfo()->baseattacktime; uint32 attackTimer = GetCreatureInfo()->MeleeBaseAttackTime;
SetAttackTime(BASE_ATTACK, attackTimer); SetAttackTime(BASE_ATTACK, attackTimer);
SetAttackTime(OFF_ATTACK, attackTimer - attackTimer / 4); SetAttackTime(OFF_ATTACK, attackTimer - attackTimer / 4);
SetAttackTime(RANGED_ATTACK, GetCreatureInfo()->rangeattacktime); SetAttackTime(RANGED_ATTACK, GetCreatureInfo()->RangedBaseAttackTime);
uint32 unitFlags = GetCreatureInfo()->unit_flags; uint32 unitFlags = GetCreatureInfo()->UnitFlags;
uint32 unitFlags2 = GetCreatureInfo()->unit_flags2; uint32 unitFlags2 = GetCreatureInfo()->UnitFlags2;
// we may need to append or remove additional flags // we may need to append or remove additional flags
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT)) if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT))
@ -406,15 +404,15 @@ bool Creature::UpdateEntry(uint32 Entry, Team team, const CreatureData* data /*=
// preserve all current dynamic flags if exist // preserve all current dynamic flags if exist
uint32 dynFlags = GetUInt32Value(UNIT_DYNAMIC_FLAGS); uint32 dynFlags = GetUInt32Value(UNIT_DYNAMIC_FLAGS);
SetUInt32Value(UNIT_DYNAMIC_FLAGS, dynFlags ? dynFlags : GetCreatureInfo()->dynamicflags); SetUInt32Value(UNIT_DYNAMIC_FLAGS, dynFlags ? dynFlags : GetCreatureInfo()->DynamicFlags);
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(GetCreatureInfo()->armor)); SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(GetCreatureInfo()->Armor));
SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(GetCreatureInfo()->resistance1)); SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(GetCreatureInfo()->ResistanceHoly));
SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(GetCreatureInfo()->resistance2)); SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(GetCreatureInfo()->ResistanceFire));
SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(GetCreatureInfo()->resistance3)); SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(GetCreatureInfo()->ResistanceNature));
SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(GetCreatureInfo()->resistance4)); SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(GetCreatureInfo()->ResistanceFrost));
SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(GetCreatureInfo()->resistance5)); SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(GetCreatureInfo()->ResistanceShadow));
SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(GetCreatureInfo()->resistance6)); SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(GetCreatureInfo()->ResistanceArcane));
SetCanModifyStats(true); SetCanModifyStats(true);
UpdateAllStats(); UpdateAllStats();
@ -518,6 +516,7 @@ void Creature::Update(uint32 update_diff, uint32 diff)
{ {
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Respawning..."); DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Respawning...");
m_respawnTime = 0; m_respawnTime = 0;
m_aggroDelay = sWorld.getConfig(CONFIG_UINT32_CREATURE_RESPAWN_AGGRO_DELAY);
lootForPickPocketed = false; lootForPickPocketed = false;
lootForBody = false; lootForBody = false;
lootForSkin = false; lootForSkin = false;
@ -535,6 +534,7 @@ void Creature::Update(uint32 update_diff, uint32 diff)
CreatureInfo const* cinfo = GetCreatureInfo(); CreatureInfo const* cinfo = GetCreatureInfo();
SelectLevel(cinfo); SelectLevel(cinfo);
UpdateAllStats(); // to be sure stats is correct regarding level of the creature
SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE); SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE);
if (m_IsDeadByDefault) if (m_IsDeadByDefault)
{ {
@ -584,6 +584,11 @@ void Creature::Update(uint32 update_diff, uint32 diff)
} }
case ALIVE: case ALIVE:
{ {
if (m_aggroDelay <= update_diff)
m_aggroDelay = 0;
else
m_aggroDelay -= update_diff;
if (m_IsDeadByDefault) if (m_IsDeadByDefault)
{ {
if (m_corpseDecayTimer <= update_diff) if (m_corpseDecayTimer <= update_diff)
@ -819,7 +824,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
return false; return false;
// pet trainers not have spells in fact now // pet trainers not have spells in fact now
if (GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS) if (GetCreatureInfo()->TrainerType != TRAINER_TYPE_PETS)
{ {
TrainerSpellData const* cSpells = GetTrainerSpells(); TrainerSpellData const* cSpells = GetTrainerSpells();
TrainerSpellData const* tSpells = GetTrainerTemplateSpells(); TrainerSpellData const* tSpells = GetTrainerTemplateSpells();
@ -833,15 +838,15 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
} }
} }
switch (GetCreatureInfo()->trainer_type) switch (GetCreatureInfo()->TrainerType)
{ {
case TRAINER_TYPE_CLASS: case TRAINER_TYPE_CLASS:
if (pPlayer->getClass() != GetCreatureInfo()->trainer_class) if (pPlayer->getClass() != GetCreatureInfo()->TrainerClass)
{ {
if (msg) if (msg)
{ {
pPlayer->PlayerTalkClass->ClearMenus(); pPlayer->PlayerTalkClass->ClearMenus();
switch (GetCreatureInfo()->trainer_class) switch (GetCreatureInfo()->TrainerClass)
{ {
case CLASS_DRUID: pPlayer->PlayerTalkClass->SendGossipMenu(4913, GetObjectGuid()); break; case CLASS_DRUID: pPlayer->PlayerTalkClass->SendGossipMenu(4913, GetObjectGuid()); break;
case CLASS_HUNTER: pPlayer->PlayerTalkClass->SendGossipMenu(10090, GetObjectGuid()); break; case CLASS_HUNTER: pPlayer->PlayerTalkClass->SendGossipMenu(10090, GetObjectGuid()); break;
@ -869,7 +874,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
} }
break; break;
case TRAINER_TYPE_MOUNTS: case TRAINER_TYPE_MOUNTS:
if (GetCreatureInfo()->trainer_race && pPlayer->getRace() != GetCreatureInfo()->trainer_race) if (GetCreatureInfo()->TrainerRace && pPlayer->getRace() != GetCreatureInfo()->TrainerRace)
{ {
// Allowed to train if exalted // Allowed to train if exalted
if (FactionTemplateEntry const* faction_template = getFactionTemplateEntry()) if (FactionTemplateEntry const* faction_template = getFactionTemplateEntry())
@ -881,7 +886,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
if (msg) if (msg)
{ {
pPlayer->PlayerTalkClass->ClearMenus(); pPlayer->PlayerTalkClass->ClearMenus();
switch (GetCreatureInfo()->trainer_class) switch (GetCreatureInfo()->TrainerClass)
{ {
case RACE_DWARF: pPlayer->PlayerTalkClass->SendGossipMenu(5865, GetObjectGuid()); break; case RACE_DWARF: pPlayer->PlayerTalkClass->SendGossipMenu(5865, GetObjectGuid()); break;
case RACE_GNOME: pPlayer->PlayerTalkClass->SendGossipMenu(4881, GetObjectGuid()); break; case RACE_GNOME: pPlayer->PlayerTalkClass->SendGossipMenu(4881, GetObjectGuid()); break;
@ -899,7 +904,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
} }
break; break;
case TRAINER_TYPE_TRADESKILLS: case TRAINER_TYPE_TRADESKILLS:
if (GetCreatureInfo()->trainer_spell && !pPlayer->HasSpell(GetCreatureInfo()->trainer_spell)) if (GetCreatureInfo()->TrainerSpell && !pPlayer->HasSpell(GetCreatureInfo()->TrainerSpell))
{ {
if (msg) if (msg)
{ {
@ -953,8 +958,8 @@ bool Creature::CanInteractWithBattleMaster(Player* pPlayer, bool msg) const
bool Creature::CanTrainAndResetTalentsOf(Player* pPlayer) const bool Creature::CanTrainAndResetTalentsOf(Player* pPlayer) const
{ {
return pPlayer->getLevel() >= 10 return pPlayer->getLevel() >= 10
&& GetCreatureInfo()->trainer_type == TRAINER_TYPE_CLASS && GetCreatureInfo()->TrainerType == TRAINER_TYPE_CLASS
&& pPlayer->getClass() == GetCreatureInfo()->trainer_class; && pPlayer->getClass() == GetCreatureInfo()->TrainerType;
} }
void Creature::PrepareBodyLootState() void Creature::PrepareBodyLootState()
@ -965,9 +970,9 @@ void Creature::PrepareBodyLootState()
if (!lootForBody) if (!lootForBody)
{ {
// have normal loot // have normal loot
if (GetCreatureInfo()->maxgold > 0 || GetCreatureInfo()->lootid || if (GetCreatureInfo()->MaxLootGold > 0 || GetCreatureInfo()->LootId ||
// ... or can have skinning after // ... or can have skinning after
(GetCreatureInfo()->SkinLootId && sWorld.getConfig(CONFIG_BOOL_CORPSE_EMPTY_LOOT_SHOW))) (GetCreatureInfo()->SkinningLootId && sWorld.getConfig(CONFIG_BOOL_CORPSE_EMPTY_LOOT_SHOW)))
{ {
SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
return; return;
@ -977,7 +982,7 @@ void Creature::PrepareBodyLootState()
lootForBody = true; // pass this loot mode lootForBody = true; // pass this loot mode
// if not have normal loot allow skinning if need // if not have normal loot allow skinning if need
if (!lootForSkin && GetCreatureInfo()->SkinLootId) if (!lootForSkin && GetCreatureInfo()->SkinningLootId)
{ {
RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
@ -1162,25 +1167,59 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
WorldDatabase.CommitTransaction(); WorldDatabase.CommitTransaction();
} }
void Creature::SelectLevel(const CreatureInfo* cinfo, float percentHealth, float percentMana)
void Creature::SelectLevel(const CreatureInfo* cinfo, float percentHealth /*= 100.0f*/)
{ {
uint32 rank = IsPet() ? 0 : cinfo->Rank; uint32 rank = IsPet() ? 0 : cinfo->Rank; // TODO :: IsPet probably not needed here
// level // level
uint32 minlevel = std::min(cinfo->maxlevel, cinfo->minlevel); uint32 const minlevel = cinfo->MinLevel;
uint32 maxlevel = std::max(cinfo->maxlevel, cinfo->minlevel); uint32 const maxlevel = cinfo->MaxLevel;
uint32 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel); uint32 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel);
SetLevel(level); SetLevel(level);
//////////////////////////////////////////////////////////////////////////
// Calculate level dependend stats
//////////////////////////////////////////////////////////////////////////
uint32 health;
uint32 mana;
if (CreatureClassLvlStats const* cCLS = sObjectMgr.GetCreatureClassLvlStats(level, cinfo->UnitClass, cinfo->Expansion))
{
// Use Creature Stats to calculate stat values
// health
health = cCLS->BaseHealth * cinfo->HealthMultiplier;
// mana
mana = cCLS->BaseMana * cinfo->PowerMultiplier;
}
else
{
// Use old style to calculate stat values
float rellevel = maxlevel == minlevel ? 0 : (float(level - minlevel)) / (maxlevel - minlevel); float rellevel = maxlevel == minlevel ? 0 : (float(level - minlevel)) / (maxlevel - minlevel);
// health // health
float healthmod = _GetHealthMod(rank); uint32 minhealth = std::min(cinfo->MaxLevelHealth, cinfo->MinLevelHealth);
uint32 maxhealth = std::max(cinfo->MaxLevelHealth, cinfo->MinLevelHealth);
health = uint32(minhealth + uint32(rellevel * (maxhealth - minhealth)));
uint32 minhealth = std::min(cinfo->maxhealth, cinfo->minhealth); // mana
uint32 maxhealth = std::max(cinfo->maxhealth, cinfo->minhealth); uint32 minmana = std::min(cinfo->MaxLevelMana, cinfo->MinLevelMana);
uint32 health = uint32(healthmod * (minhealth + uint32(rellevel * (maxhealth - minhealth)))); uint32 maxmana = std::max(cinfo->MaxLevelMana, cinfo->MinLevelMana);
mana = minmana + uint32(rellevel * (maxmana - minmana));
}
health *= _GetHealthMod(rank); // Apply custom config settting
if (health < 1)
health = 1;
//////////////////////////////////////////////////////////////////////////
// Set values
//////////////////////////////////////////////////////////////////////////
// health
SetCreateHealth(health); SetCreateHealth(health);
SetMaxHealth(health); SetMaxHealth(health);
@ -1189,33 +1228,51 @@ void Creature::SelectLevel(const CreatureInfo* cinfo, float percentHealth, float
else else
SetHealthPercent(percentHealth); SetHealthPercent(percentHealth);
// mana
uint32 minmana = std::min(cinfo->maxmana, cinfo->minmana);
uint32 maxmana = std::max(cinfo->maxmana, cinfo->minmana);
uint32 mana = minmana + uint32(rellevel * (maxmana - minmana));
SetCreateMana(mana);
SetMaxPower(POWER_MANA, mana); // MAX Mana
SetPower(POWER_MANA, mana);
// TODO: set UNIT_FIELD_POWER*, for some creature class case (energy, etc)
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, float(health)); SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, float(health));
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, float(mana));
// all power types
for (int i = POWER_MANA; i <= POWER_RUNIC_POWER; ++i)
{
uint32 maxValue = 0;
switch (i)
{
case POWER_MANA: maxValue = mana; break;
case POWER_RAGE: maxValue = 0; break;
case POWER_FOCUS: maxValue = POWER_FOCUS_DEFAULT; break;
case POWER_ENERGY: maxValue = POWER_ENERGY_DEFAULT * cinfo->PowerMultiplier; break;
case POWER_RUNE: maxValue = 0; break;
case POWER_RUNIC_POWER: maxValue = 0; break;
}
uint32 value = maxValue;
// For non regenerating powers set 0
if ((i == POWER_ENERGY || i == POWER_MANA) && !IsRegeneratingPower())
value = 0;
// Mana requires an extra field to be set
if (i == POWER_MANA)
SetCreateMana(value);
SetMaxPower(Powers(i), maxValue);
SetPower(Powers(i), value);
SetModifierValue(UnitMods(UNIT_MOD_POWER_START + i), BASE_VALUE, float(value));
}
// damage // damage
float damagemod = _GetDamageMod(rank); float damagemod = _GetDamageMod(rank);
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod); SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->MinMeleeDmg * damagemod);
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod); SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->MaxMeleeDmg * damagemod);
SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod); SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->MinMeleeDmg * damagemod);
SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod); SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, cinfo->MaxMeleeDmg * damagemod);
SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, cinfo->minrangedmg * damagemod); SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, cinfo->MinRangedDmg * damagemod);
SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, cinfo->maxrangedmg * damagemod); SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, cinfo->MaxRangedDmg * damagemod);
SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->attackpower * damagemod); SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->MeleeAttackPower * damagemod);
} }
float Creature::_GetHealthMod(int32 Rank) float Creature::_GetHealthMod(int32 Rank)
@ -1370,7 +1427,7 @@ bool Creature::LoadFromDB(uint32 guidlow, Map* map)
SetHealth(m_deathState == ALIVE ? curhealth : 0); SetHealth(m_deathState == ALIVE ? curhealth : 0);
SetPower(POWER_MANA, data->curmana); SetPower(POWER_MANA, data->curmana);
SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->dmgschool)); SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->DamageSchool));
// checked at creature_template loading // checked at creature_template loading
m_defaultMovementType = MovementGeneratorType(data->movementType); m_defaultMovementType = MovementGeneratorType(data->movementType);
@ -1561,7 +1618,7 @@ void Creature::SetDeathState(DeathState s)
if (GetTemporaryFactionFlags() & TEMPFACTION_RESTORE_RESPAWN) if (GetTemporaryFactionFlags() & TEMPFACTION_RESTORE_RESPAWN)
ClearTemporaryFaction(); ClearTemporaryFaction();
SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->dmgschool)); SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->DamageSchool));
// Dynamic flags may be adjusted by spells. Clear them // Dynamic flags may be adjusted by spells. Clear them
// first and let spell from *addon apply where needed. // first and let spell from *addon apply where needed.
@ -1570,7 +1627,7 @@ void Creature::SetDeathState(DeathState s)
// Flags after LoadCreatureAddon. Any spell in *addon // Flags after LoadCreatureAddon. Any spell in *addon
// will not be able to adjust these. // will not be able to adjust these.
SetUInt32Value(UNIT_NPC_FLAGS, GetCreatureInfo()->npcflag); SetUInt32Value(UNIT_NPC_FLAGS, GetCreatureInfo()->NpcFlags);
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
SetWalk(true, true); SetWalk(true, true);
@ -1634,7 +1691,7 @@ bool Creature::IsImmuneToSpellEffect(SpellEntry const* spellInfo, SpellEffectInd
return true; return true;
// Taunt immunity special flag check // Taunt immunity special flag check
if (GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NOT_TAUNTABLE) if (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NOT_TAUNTABLE)
{ {
// Taunt aura apply check // Taunt aura apply check
if (spellEffect->Effect == SPELL_EFFECT_APPLY_AURA) if (spellEffect->Effect == SPELL_EFFECT_APPLY_AURA)
@ -1775,7 +1832,7 @@ bool Creature::IsVisibleInGridForPlayer(Player* pl) const
if (pl->isGameMaster()) if (pl->isGameMaster())
return true; return true;
if (GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_INVISIBLE) if (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_INVISIBLE)
return false; return false;
// Live player (or with not release body see live creatures or death creatures with corpse disappearing time > 0 // Live player (or with not release body see live creatures or death creatures with corpse disappearing time > 0
@ -1822,6 +1879,10 @@ void Creature::CallAssistance()
if (!m_AlreadyCallAssistance && getVictim() && !IsCharmed()) if (!m_AlreadyCallAssistance && getVictim() && !IsCharmed())
{ {
SetNoCallAssistance(true); SetNoCallAssistance(true);
if (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CALL_ASSIST)
return;
AI()->SendAIEventAround(AI_EVENT_CALL_ASSISTANCE, getVictim(), sWorld.getConfig(CONFIG_UINT32_CREATURE_FAMILY_ASSISTANCE_DELAY), sWorld.getConfig(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS)); AI()->SendAIEventAround(AI_EVENT_CALL_ASSISTANCE, getVictim(), sWorld.getConfig(CONFIG_UINT32_CREATURE_FAMILY_ASSISTANCE_DELAY), sWorld.getConfig(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS));
} }
} }
@ -1888,6 +1949,12 @@ bool Creature::CanInitiateAttack()
if (isPassiveToHostile()) if (isPassiveToHostile())
return false; return false;
if (m_aggroDelay != 0)
return false;
if (!CanAttackByItself())
return false;
return true; return true;
} }
@ -2350,8 +2417,8 @@ VendorItemData const* Creature::GetVendorItems() const
VendorItemData const* Creature::GetVendorTemplateItems() const VendorItemData const* Creature::GetVendorTemplateItems() const
{ {
uint32 vendorId = GetCreatureInfo()->vendorId; uint32 VendorTemplateId = GetCreatureInfo()->VendorTemplateId;
return vendorId ? sObjectMgr.GetNpcVendorTemplateItemList(vendorId) : NULL; return VendorTemplateId ? sObjectMgr.GetNpcVendorTemplateItemList(VendorTemplateId) : NULL;
} }
uint32 Creature::GetVendorItemCurrentCount(VendorItem const* vItem) uint32 Creature::GetVendorItemCurrentCount(VendorItem const* vItem)
@ -2428,8 +2495,8 @@ uint32 Creature::UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 us
TrainerSpellData const* Creature::GetTrainerTemplateSpells() const TrainerSpellData const* Creature::GetTrainerTemplateSpells() const
{ {
uint32 trainerId = GetCreatureInfo()->trainerId; uint32 TrainerTemplateId = GetCreatureInfo()->TrainerTemplateId;
return trainerId ? sObjectMgr.GetNpcTrainerTemplateSpells(trainerId) : NULL; return TrainerTemplateId ? sObjectMgr.GetNpcTrainerTemplateSpells(TrainerTemplateId) : NULL;
} }
TrainerSpellData const* Creature::GetTrainerSpells() const TrainerSpellData const* Creature::GetTrainerSpells() const
@ -2469,11 +2536,11 @@ void Creature::ClearTemporaryFaction()
// Reset to original faction // Reset to original faction
setFaction(GetCreatureInfo()->FactionAlliance); setFaction(GetCreatureInfo()->FactionAlliance);
// Reset UNIT_FLAG_NON_ATTACKABLE, UNIT_FLAG_OOC_NOT_ATTACKABLE or UNIT_FLAG_PASSIVE flags // Reset UNIT_FLAG_NON_ATTACKABLE, UNIT_FLAG_OOC_NOT_ATTACKABLE or UNIT_FLAG_PASSIVE flags
if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_NON_ATTACKABLE && GetCreatureInfo()->unit_flags & UNIT_FLAG_NON_ATTACKABLE) if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_NON_ATTACKABLE && GetCreatureInfo()->UnitFlags & UNIT_FLAG_NON_ATTACKABLE)
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK && GetCreatureInfo()->unit_flags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !IsInCombat()) if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK && GetCreatureInfo()->UnitFlags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !IsInCombat())
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE);
if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_PASSIVE && GetCreatureInfo()->unit_flags & UNIT_FLAG_PASSIVE) if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_PASSIVE && GetCreatureInfo()->UnitFlags & UNIT_FLAG_PASSIVE)
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE);
m_temporaryFactionFlags = TEMPFACTION_NONE; m_temporaryFactionFlags = TEMPFACTION_NONE;

View file

@ -49,17 +49,23 @@ struct GameEventCreatureData;
enum CreatureFlagsExtra enum CreatureFlagsExtra
{ {
CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group CREATURE_EXTRA_FLAG_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group
CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility) CREATURE_EXTRA_FLAG_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility)
CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry CREATURE_EXTRA_FLAG_NO_PARRY = 0x00000004, // creature can't parry
CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry CREATURE_EXTRA_FLAG_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry
CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block CREATURE_EXTRA_FLAG_NO_BLOCK = 0x00000010, // creature can't block
CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks CREATURE_EXTRA_FLAG_NO_CRUSH = 0x00000020, // creature can't do crush attacks
CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP CREATURE_EXTRA_FLAG_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP
CREATURE_FLAG_EXTRA_INVISIBLE = 0x00000080, // creature is always invisible for player (mostly trigger creatures) CREATURE_EXTRA_FLAG_INVISIBLE = 0x00000080, // creature is always invisible for player (mostly trigger creatures)
CREATURE_FLAG_EXTRA_NOT_TAUNTABLE = 0x00000100, // creature is immune to taunt auras and effect attack me CREATURE_EXTRA_FLAG_NOT_TAUNTABLE = 0x00000100, // creature is immune to taunt auras and effect attack me
CREATURE_FLAG_EXTRA_AGGRO_ZONE = 0x00000200, // creature sets itself in combat with zone on aggro CREATURE_EXTRA_FLAG_AGGRO_ZONE = 0x00000200, // creature sets itself in combat with zone on aggro
CREATURE_FLAG_EXTRA_GUARD = 0x00000400, // creature is a guard CREATURE_EXTRA_FLAG_GUARD = 0x00000400, // creature is a guard
CREATURE_EXTRA_FLAG_NO_CALL_ASSIST = 0x00000800, // creature shouldn't call for assistance on aggro
CREATURE_EXTRA_FLAG_ACTIVE = 0x00001000, // creature is active object. Grid of this creature will be loaded and creature set as active
CREATURE_EXTRA_FLAG_MMAP_FORCE_ENABLE = 0x00002000, // creature is forced to use MMaps
CREATURE_EXTRA_FLAG_MMAP_FORCE_DISABLE = 0x00004000, // creature is forced to NOT use MMaps
CREATURE_EXTRA_FLAG_WALK_IN_WATER = 0x00008000, // creature is forced to walk in water even it can swim
CREATURE_EXTRA_FLAG_HAVE_NO_SWIM_ANIMATION = 0x00010000, // we have to not set "swim" animation or creature will have "no animation"
}; };
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform // GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform
@ -72,8 +78,124 @@ enum CreatureFlagsExtra
#define MAX_KILL_CREDIT 2 #define MAX_KILL_CREDIT 2
#define MAX_CREATURE_MODEL 4 #define MAX_CREATURE_MODEL 4
// from `creature_template` table // from `creature_template` table
struct CreatureInfo struct CreatureInfo
{
uint32 Entry;
char* Name;
char* SubName;
char* IconName;
uint32 MinLevel;
uint32 MaxLevel;
uint32 DifficultyEntry[MAX_DIFFICULTY - 1];
uint32 ModelId[MAX_CREATURE_MODEL];
uint32 FactionAlliance;
uint32 FactionHorde;
float Scale;
uint32 Family; // enum CreatureFamily values (optional)
uint32 CreatureType; // enum CreatureType values
uint32 InhabitType;
uint32 RegenerateStats;
bool RacialLeader;
uint32 NpcFlags;
uint32 UnitFlags; // enum UnitFlags mask values
uint32 UnitFlags2; // enum UnitFlags2 mask values
uint32 DynamicFlags;
uint32 ExtraFlags;
uint32 CreatureTypeFlags; // enum CreatureTypeFlags mask values
float SpeedWalk;
float SpeedRun;
uint32 UnitClass; // enum Classes. Note only 4 classes are known for creatures.
uint32 Rank;
int32 Expansion; // creature expansion, important for stats, CAN BE -1 as marker for some invalid cases.
float HealthMultiplier;
float PowerMultiplier;
float DamageMultiplier;
float DamageVariance;
float ArmorMultiplier;
float ExperienceMultiplier;
uint32 MinLevelHealth;
uint32 MaxLevelHealth;
uint32 MinLevelMana;
uint32 MaxLevelMana;
float MinMeleeDmg;
float MaxMeleeDmg;
float MinRangedDmg;
float MaxRangedDmg;
uint32 Armor;
uint32 MeleeAttackPower;
uint32 RangedAttackPower;
uint32 MeleeBaseAttackTime;
uint32 RangedBaseAttackTime;
uint32 DamageSchool;
uint32 MinLootGold;
uint32 MaxLootGold;
uint32 LootId;
uint32 PickpocketLootId;
uint32 SkinningLootId;
uint32 KillCredit[MAX_KILL_CREDIT];
uint32 QuestItems[6];
uint32 MechanicImmuneMask;
int32 ResistanceHoly;
int32 ResistanceFire;
int32 ResistanceNature;
int32 ResistanceFrost;
int32 ResistanceShadow;
int32 ResistanceArcane;
uint32 PetSpellDataId;
uint32 MovementType;
uint32 MovementTemplateId;
uint32 TrainerType;
uint32 TrainerSpell;
uint32 TrainerClass;
uint32 TrainerRace;
uint32 TrainerTemplateId;
uint32 VendorTemplateId;
uint32 EquipmentTemplateId;
uint32 VehicleTemplateId;
uint32 GossipMenuId;
char const* AIName;
// helpers
HighGuid GetHighGuid() const
{
return VehicleTemplateId ? HIGHGUID_VEHICLE : HIGHGUID_UNIT;
}
ObjectGuid GetObjectGuid(uint32 lowguid) const { return ObjectGuid(GetHighGuid(), Entry, lowguid); }
SkillType GetRequiredLootSkill() const
{
if (CreatureTypeFlags & CREATURE_TYPEFLAGS_HERBLOOT)
return SKILL_HERBALISM;
else if (CreatureTypeFlags & CREATURE_TYPEFLAGS_MININGLOOT)
return SKILL_MINING;
else if (CreatureTypeFlags & CREATURE_TYPEFLAGS_ENGINEERLOOT)
return SKILL_ENGINEERING;
else
return SKILL_SKINNING; // normal case
}
bool IsExotic() const
{
return (CreatureTypeFlags & CREATURE_TYPEFLAGS_EXOTIC);
}
bool isTameable(bool exotic) const
{
if (CreatureType != CREATURE_TYPE_BEAST || Family == 0 || (CreatureTypeFlags & CREATURE_TYPEFLAGS_TAMEABLE) == 0)
return false;
// if can tame exotic then can tame any temable
return exotic || !IsExotic();
}
};
// from `creature_template` table
/*
struct CreatureInfo
{ {
uint32 Entry; uint32 Entry;
uint32 DifficultyEntry[MAX_DIFFICULTY - 1]; uint32 DifficultyEntry[MAX_DIFFICULTY - 1];
@ -83,16 +205,16 @@ struct CreatureInfo
char* SubName; char* SubName;
char* IconName; char* IconName;
uint32 GossipMenuId; uint32 GossipMenuId;
uint32 minlevel; uint32 MinLevel;
uint32 maxlevel; uint32 MaxLevel;
uint32 minhealth; uint32 MinLevelHealth;
uint32 maxhealth; uint32 maxhealth;
uint32 minmana; uint32 MinLevelMana;
uint32 maxmana; uint32 maxmana;
uint32 armor; uint32 armor;
uint32 FactionAlliance; uint32 FactionAlliance;
uint32 FactionHorde; uint32 FactionHorde;
uint32 npcflag; uint32 NpcFlags;
float speed_walk; float speed_walk;
float speed_run; float speed_run;
float Scale; float Scale;
@ -102,25 +224,25 @@ struct CreatureInfo
uint32 dmgschool; uint32 dmgschool;
uint32 attackpower; uint32 attackpower;
float dmg_multiplier; float dmg_multiplier;
uint32 baseattacktime; uint32 MeleeAttackPower;
uint32 rangeattacktime; uint32 RangedAttackPower;
uint32 unit_class; // enum Classes. Note only 4 classes are known for creatures. uint32 UnitClass; // enum Classes. Note only 4 classes are known for creatures.
uint32 unit_flags; // enum UnitFlags mask values uint32 UnitFlags; // enum UnitFlags mask values
uint32 unit_flags2; // enum UnitFlags2 mask values uint32 UnitFlags2; // enum UnitFlags2 mask values
uint32 dynamicflags; uint32 dynamicflags;
uint32 family; // enum CreatureFamily values (optional) uint32 family; // enum CreatureFamily values (optional)
uint32 trainer_type; uint32 TrainerType;
uint32 trainer_spell; uint32 trainer_spell;
uint32 trainer_class; uint32 TrainerClass;
uint32 trainer_race; uint32 trainer_race;
float minrangedmg; float minrangedmg;
float maxrangedmg; float maxrangedmg;
uint32 rangedattackpower; uint32 rangedattackpower;
uint32 type; // enum CreatureType values uint32 type; // enum CreatureType values
uint32 CreatureTypeFlags; // enum CreatureTypeFlags mask values uint32 CreatureTypeFlags; // enum CreatureTypeFlags mask values
uint32 lootid; uint32 Lootid;
uint32 pickpocketLootId; uint32 pickpocketLootId;
uint32 SkinLootId; uint32 SkinningLootId;
int32 resistance1; int32 resistance1;
int32 resistance2; int32 resistance2;
int32 resistance3; int32 resistance3;
@ -128,7 +250,7 @@ struct CreatureInfo
int32 resistance5; int32 resistance5;
int32 resistance6; int32 resistance6;
uint32 PetSpellDataId; uint32 PetSpellDataId;
uint32 mingold; uint32 MinLootGold;
uint32 maxgold; uint32 maxgold;
char const* AIName; char const* AIName;
uint32 MovementType; uint32 MovementType;
@ -141,8 +263,8 @@ struct CreatureInfo
bool RegenHealth; bool RegenHealth;
uint32 VehicleTemplateId; uint32 VehicleTemplateId;
uint32 EquipmentTemplateId; uint32 EquipmentTemplateId;
uint32 trainerId; uint32 TrainerTemplateId;
uint32 vendorId; uint32 VendorTemplateId;
uint32 MechanicImmuneMask; uint32 MechanicImmuneMask;
uint32 ExtraFlags; uint32 ExtraFlags;
@ -179,7 +301,7 @@ struct CreatureInfo
// if can tame exotic then can tame any temable // if can tame exotic then can tame any temable
return exotic || !IsExotic(); return exotic || !IsExotic();
} }
}; }; */
struct CreatureTemplateSpells struct CreatureTemplateSpells
{ {
@ -330,6 +452,12 @@ enum SelectFlags
SELECT_FLAG_NOT_IN_MELEE_RANGE = 0x080, SELECT_FLAG_NOT_IN_MELEE_RANGE = 0x080,
}; };
enum RegenStatsFlags
{
REGEN_FLAG_HEALTH = 0x001,
REGEN_FLAG_POWER = 0x002,
};
// Vendors // Vendors
enum enum
@ -501,7 +629,7 @@ class Creature : public Unit
bool Create(uint32 guidlow, CreatureCreatePos& cPos, CreatureInfo const* cinfo, Team team = TEAM_NONE, const CreatureData* data = NULL, GameEventCreatureData const* eventData = NULL); bool Create(uint32 guidlow, CreatureCreatePos& cPos, CreatureInfo const* cinfo, Team team = TEAM_NONE, const CreatureData* data = NULL, GameEventCreatureData const* eventData = NULL);
bool LoadCreatureAddon(bool reload); bool LoadCreatureAddon(bool reload);
void SelectLevel(const CreatureInfo* cinfo, float percentHealth = 100.0f, float percentMana = 100.0f); void SelectLevel(const CreatureInfo* cinfo, float percentHealth = 100.0f);
void LoadEquipment(uint32 equip_entry, bool force = false); void LoadEquipment(uint32 equip_entry, bool force = false);
bool HasStaticDBSpawnData() const; // listed in `creature` table and have fixed in DB guid bool HasStaticDBSpawnData() const; // listed in `creature` table and have fixed in DB guid
@ -523,12 +651,14 @@ class Creature : public Unit
void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; } void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
uint32 GetCorpseDelay() const { return m_corpseDelay; } uint32 GetCorpseDelay() const { return m_corpseDelay; }
bool IsRacialLeader() const { return GetCreatureInfo()->RacialLeader; } bool IsRacialLeader() const { return GetCreatureInfo()->RacialLeader; }
bool IsCivilian() const { return GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_CIVILIAN; } bool IsCivilian() const { return GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_CIVILIAN; }
bool IsGuard() const { return GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_GUARD; } bool IsGuard() const { return GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_GUARD; }
bool CanWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; } bool CanWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; }
virtual bool CanSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; } bool CanSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; }
bool CanFly() const { return (GetCreatureInfo()->InhabitType & INHABIT_AIR) || (GetByteValue(UNIT_FIELD_BYTES_1, 3) & UNIT_BYTE1_FLAG_FLY_ANIM) || HasAuraType(SPELL_AURA_FLY); } bool IsSwimming() const { return (m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_SWIMMING))); }
bool CanFly() const { return (GetCreatureInfo()->InhabitType & INHABIT_AIR) || (GetByteValue(UNIT_FIELD_BYTES_1, 3) & UNIT_BYTE1_FLAG_FLY_ANIM) || m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_LEVITATING | MOVEFLAG_CAN_FLY)); }
bool IsFlying() const { return (m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_FLYING | MOVEFLAG_LEVITATING))); }
bool IsTrainerOf(Player* player, bool msg) const; bool IsTrainerOf(Player* player, bool msg) const;
bool CanInteractWithBattleMaster(Player* player, bool msg) const; bool CanInteractWithBattleMaster(Player* player, bool msg) const;
@ -745,7 +875,8 @@ class Creature : public Unit
bool HasInvolvedQuest(uint32 quest_id) const override; bool HasInvolvedQuest(uint32 quest_id) const override;
GridReference<Creature>& GetGridRef() { return m_gridRef; } GridReference<Creature>& GetGridRef() { return m_gridRef; }
bool IsRegeneratingHealth() { return m_regenHealth; } bool IsRegeneratingHealth() { return GetCreatureInfo()->RegenerateStats & REGEN_FLAG_HEALTH; }
bool IsRegeneratingPower() { return GetCreatureInfo()->RegenerateStats & REGEN_FLAG_POWER; }
virtual uint8 GetPetAutoSpellSize() const { return CREATURE_MAX_SPELLS; } virtual uint8 GetPetAutoSpellSize() const { return CREATURE_MAX_SPELLS; }
virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const
{ {
@ -802,6 +933,7 @@ class Creature : public Unit
time_t m_respawnTime; // (secs) time of next respawn time_t m_respawnTime; // (secs) time of next respawn
uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning
uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance
uint32 m_aggroDelay; // (msecs)delay between respawn and aggro due to movement
float m_respawnradius; float m_respawnradius;
CreatureSubtype m_subtype; // set in Creatures subclasses for fast it detect without dynamic_cast use CreatureSubtype m_subtype; // set in Creatures subclasses for fast it detect without dynamic_cast use

View file

@ -732,7 +732,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
break; break;
case ACTION_T_COMBAT_MOVEMENT: case ACTION_T_COMBAT_MOVEMENT:
// ignore no affect case // ignore no affect case
if (m_isCombatMovement == (action.combat_movement.state != 0)) if (m_isCombatMovement == (action.combat_movement.state != 0) || m_creature->IsNonMeleeSpellCasted(false))
return; return;
SetCombatMovement(action.combat_movement.state != 0, true); SetCombatMovement(action.combat_movement.state != 0, true);
@ -966,63 +966,38 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
m_throwAIEventMask = action.setThrowMask.eventTypeMask; m_throwAIEventMask = action.setThrowMask.eventTypeMask;
break; break;
} }
case ACTION_T_SUMMON_UNIQUE: case ACTION_T_SET_STAND_STATE:
{ {
Creature* pCreature = NULL; m_creature->SetStandState(action.setStandState.standState);
MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_creature, action.summon_unique.creatureId, true, false, 100, true);
MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(pCreature, u_check);
Cell::VisitGridObjects(m_creature, searcher, 100);
WorldObject* pSpawn = NULL;
pSpawn = pCreature;
if (!pSpawn)
{
Unit* target = GetTargetByType(action.summon_unique.target, pActionInvoker, pAIEventSender, reportTargetError);
if (!target && reportTargetError)
sLog.outErrorEventAI("Event %u - NULL target for ACTION_T_SUMMON_UNIQUE(%u), target-type %u", EventId, action.type, action.summon_unique.target);
CreatureEventAI_Summon_Map::const_iterator i = sEventAIMgr.GetCreatureEventAISummonMap().find(action.summon_unique.spawnId);
if (i == sEventAIMgr.GetCreatureEventAISummonMap().end())
{
sLog.outErrorEventAI("Failed to spawn creature %u. Summon map index %u does not exist. EventID %d. CreatureID %d", action.summon_unique.creatureId, action.summon_unique.spawnId, EventId, m_creature->GetEntry());
return;
}
Creature* pCreature = NULL;
if ((*i).second.SpawnTimeSecs)
pCreature = m_creature->SummonCreature(action.summon_unique.creatureId, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, (*i).second.SpawnTimeSecs);
else
pCreature = m_creature->SummonCreature(action.summon_unique.creatureId, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OOC_DESPAWN, 0);
if (!pCreature)
sLog.outErrorEventAI("Failed to spawn creature %u. EventId %d.Creature %d", action.summon_unique.creatureId, EventId, m_creature->GetEntry());
else if (action.summon_unique.target != TARGET_T_SELF && target)
pCreature->AI()->AttackStart(target);
break; break;
} }
case ACTION_T_CHANGE_MOVEMENT:
if (pSpawn)
{ {
return; switch (action.changeMovement.movementType)
}
}
case ACTION_T_EMOTE_TARGET:
{ {
Unit* pCreature = m_creature->GetMap()->GetCreature(ObjectGuid(HIGHGUID_UNIT, action.emoteTarget.targetGuid)); case IDLE_MOTION_TYPE:
if (!pCreature) m_creature->GetMotionMaster()->MoveIdle();
{ break;
sLog.outErrorEventAI("Event %d. Cannot find creature by guid %d", EventId, action.emoteTarget.targetGuid); case RANDOM_MOTION_TYPE:
return; m_creature->GetMotionMaster()->MoveRandomAroundPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), float(action.changeMovement.wanderDistance));
break;
case WAYPOINT_MOTION_TYPE:
m_creature->GetMotionMaster()->MoveWaypoint();
break;
} }
break;
}
case ACTION_T_DYNAMIC_MOVEMENT:
{
if (action.dynamicMovement.state && m_DynamicMovement || !action.dynamicMovement.state && !m_DynamicMovement)
break;
m_DynamicMovement = action.dynamicMovement.state;
m_creature->SetFacingToObject(pCreature); SetCombatMovement(!m_DynamicMovement, true);
m_creature->HandleEmote(action.emoteTarget.emoteId);
break; break;
} }
default: default:
sLog.outError("CreatureEventAi::ProcessAction(): action(%u) not implemented", static_cast<uint32>(action.type));
break; break;
} }
} }

View file

@ -123,8 +123,10 @@ enum EventAI_ActionType
ACTION_T_CHANCED_TEXT = 44, // Chance to display the text, TextId1, optionally TextId2. If more than just -TextId1 is defined, randomize. Negative values. ACTION_T_CHANCED_TEXT = 44, // Chance to display the text, TextId1, optionally TextId2. If more than just -TextId1 is defined, randomize. Negative values.
ACTION_T_THROW_AI_EVENT = 45, // EventType, Radius, unused ACTION_T_THROW_AI_EVENT = 45, // EventType, Radius, unused
ACTION_T_SET_THROW_MASK = 46, // EventTypeMask, unused, unused ACTION_T_SET_THROW_MASK = 46, // EventTypeMask, unused, unused
ACTION_T_SUMMON_UNIQUE = 47, // CreatureId, Target, SpawnId ACTION_T_SET_STAND_STATE = 47, // StandState, unused, unused
ACTION_T_EMOTE_TARGET = 48, // EmoteId, TargetGuid ACTION_T_CHANGE_MOVEMENT = 48, // MovementType, WanderDistance, unused
ACTION_T_DYNAMIC_MOVEMENT = 49, // EnableDynamicMovement (1 = on; 0 = off)
ACTION_T_END, ACTION_T_END,
}; };
@ -384,7 +386,6 @@ struct CreatureEventAI_Action
uint32 creatureId; // set one from fields (or 0 for both to dismount) uint32 creatureId; // set one from fields (or 0 for both to dismount)
uint32 modelId; uint32 modelId;
} mount; } mount;
// ACTION_T_CHANCED_TEXT = 44 // ACTION_T_CHANCED_TEXT = 44
struct struct
{ {
@ -405,19 +406,27 @@ struct CreatureEventAI_Action
uint32 unused1; uint32 unused1;
uint32 unused2; uint32 unused2;
} setThrowMask; } setThrowMask;
// ACTION_T_SUMMON_UNIQUE = 47 // ACTION_T_SET_STAND_STATE = 47
struct struct
{ {
uint32 creatureId; uint32 standState;
uint32 target; uint32 unused1;
uint32 spawnId; uint32 unused2;
} summon_unique; } setStandState;
// ACTION_T_EMOTE_TARGET = 48 // ACTION_T_CHANGE_MOVEMENT = 48
struct struct
{ {
uint32 emoteId; uint32 movementType;
uint32 targetGuid; uint32 wanderDistance;
} emoteTarget; uint32 unused1;
} changeMovement;
// ACTION_T_DYNAMIC_MOVEMENT = 49
struct
{
uint32 state; // bool: 1 = on; 0 = off
uint32 unused1;
uint32 unused2;
} dynamicMovement;
// RAW // RAW
struct struct
{ {
@ -672,6 +681,8 @@ class CreatureEventAI : public CreatureAI
uint8 m_Phase; // Current phase, max 32 phases uint8 m_Phase; // Current phase, max 32 phases
bool m_MeleeEnabled; // If we allow melee auto attack bool m_MeleeEnabled; // If we allow melee auto attack
bool m_DynamicMovement; // Core will control creatures movement if this is enabled
bool m_HasOOCLoSEvent; // Cache if a OOC-LoS Event exists
uint32 m_InvinceabilityHpLevel; // Minimal health level allowed at damage apply uint32 m_InvinceabilityHpLevel; // Minimal health level allowed at damage apply
uint32 m_throwAIEventMask; // Automatically throw AIEvents that are encoded into this mask uint32 m_throwAIEventMask; // Automatically throw AIEvents that are encoded into this mask

View file

@ -873,6 +873,21 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
continue; continue;
} }
break; break;
case ACTION_T_SET_STAND_STATE:
if (action.setStandState.standState >= MAX_UNIT_STAND_STATE)
{
sLog.outErrorEventAI("Event %u Action %u uses invalid unit stand state %u (must be smaller than %u)", i, j + 1, action.setStandState.standState, MAX_UNIT_STAND_STATE);
continue;
}
break;
case ACTION_T_CHANGE_MOVEMENT:
if (action.changeMovement.movementType >= MAX_DB_MOTION_TYPE)
{
sLog.outErrorEventAI("Event %u Action %u uses invalid movement type %u (must be smaller than %u)", i, j + 1, action.changeMovement.movementType, MAX_DB_MOTION_TYPE);
continue;
}
break;
default: default:
sLog.outErrorEventAI("Event %u Action %u have currently not checked at load action type (%u). Need check code update?", i, j + 1, temp.action[j].type); sLog.outErrorEventAI("Event %u Action %u have currently not checked at load action type (%u). Need check code update?", i, j + 1, temp.action[j].type);
break; break;

View file

@ -119,7 +119,7 @@ namespace MaNGOS
{ {
if (u->GetTypeId() == TYPEID_UNIT && ( if (u->GetTypeId() == TYPEID_UNIT && (
((Creature*)u)->IsTotem() || ((Creature*)u)->IsPet() || ((Creature*)u)->IsTotem() || ((Creature*)u)->IsPet() ||
(((Creature*)u)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL))) (((Creature*)u)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_XP_AT_KILL)))
return 0; return 0;
uint32 xp_gain = BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(pl->GetMapId(), pl->GetZoneId())); uint32 xp_gain = BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(pl->GetMapId(), pl->GetZoneId()));

View file

@ -2048,30 +2048,27 @@ bool GameObject::HasStaticDBSpawnData() const
return sObjectMgr.GetGOData(GetGUIDLow()) != NULL; return sObjectMgr.GetGOData(GetGUIDLow()) != NULL;
} }
void GameObject::SetCapturePointSlider(float value) void GameObject::SetCapturePointSlider(float value, bool isLocked)
{ {
GameObjectInfo const* info = GetGOInfo(); GameObjectInfo const* info = GetGOInfo();
// only activate non-locked capture point
if (value >= 0)
{
m_captureSlider = value; m_captureSlider = value;
{ SetLootState(GO_ACTIVATED); }
} // only activate non-locked capture point
else if (!isLocked)
m_captureSlider = -value; SetLootState(GO_ACTIVATED);
// set the state of the capture point based on the slider value // set the state of the capture point based on the slider value
if ((int)m_captureSlider == CAPTURE_SLIDER_ALLIANCE) if ((int)m_captureSlider == CAPTURE_SLIDER_ALLIANCE)
{ m_captureState = CAPTURE_STATE_WIN_ALLIANCE; } m_captureState = CAPTURE_STATE_WIN_ALLIANCE;
else if ((int)m_captureSlider == CAPTURE_SLIDER_HORDE) else if ((int)m_captureSlider == CAPTURE_SLIDER_HORDE)
{ m_captureState = CAPTURE_STATE_WIN_HORDE; } m_captureState = CAPTURE_STATE_WIN_HORDE;
else if (m_captureSlider > CAPTURE_SLIDER_MIDDLE + info->capturePoint.neutralPercent * 0.5f) else if (m_captureSlider > CAPTURE_SLIDER_MIDDLE + info->capturePoint.neutralPercent * 0.5f)
{ m_captureState = CAPTURE_STATE_PROGRESS_ALLIANCE; } m_captureState = CAPTURE_STATE_PROGRESS_ALLIANCE;
else if (m_captureSlider < CAPTURE_SLIDER_MIDDLE - info->capturePoint.neutralPercent * 0.5f) else if (m_captureSlider < CAPTURE_SLIDER_MIDDLE - info->capturePoint.neutralPercent * 0.5f)
{ m_captureState = CAPTURE_STATE_PROGRESS_HORDE; } m_captureState = CAPTURE_STATE_PROGRESS_HORDE;
else else
{ m_captureState = CAPTURE_STATE_NEUTRAL; } m_captureState = CAPTURE_STATE_NEUTRAL;
} }
void GameObject::TickCapturePoint() void GameObject::TickCapturePoint()

View file

@ -622,7 +622,7 @@ enum CapturePointState
CAPTURE_STATE_WIN_HORDE CAPTURE_STATE_WIN_HORDE
}; };
enum CapturePointSlider enum CapturePointSliderValue
{ {
CAPTURE_SLIDER_ALLIANCE = 100, // full alliance CAPTURE_SLIDER_ALLIANCE = 100, // full alliance
CAPTURE_SLIDER_HORDE = 0, // full horde CAPTURE_SLIDER_HORDE = 0, // full horde
@ -796,8 +796,10 @@ class GameObject : public WorldObject
GameObject* LookupFishingHoleAround(float range); GameObject* LookupFishingHoleAround(float range);
void SetCapturePointSlider(float value); void SetCapturePointSlider(float value, bool isLocked);
float GetCapturePointSlider() const { return m_captureSlider; } float GetCapturePointSliderValue() const { return m_captureSlider; }
float GetInteractionDistance();
uint32 GetScriptId(); uint32 GetScriptId();

View file

@ -583,7 +583,7 @@ void Guild::BroadcastToGuild(WorldSession* session, const std::string& msg, uint
if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(), GR_RIGHT_GCHATSPEAK)) if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(), GR_RIGHT_GCHATSPEAK))
{ {
WorldPacket data; WorldPacket data;
ChatHandler::FillMessageData(&data, session, CHAT_MSG_GUILD, language, msg.c_str()); ChatHandler::BuildChatPacket(data, CHAT_MSG_GUILD, msg.c_str(), Language(language), session->GetPlayer()->GetChatTag(), session->GetPlayer()->GetObjectGuid(), session->GetPlayer()->GetName());
for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{ {
@ -600,7 +600,7 @@ void Guild::BroadcastAddonToGuild(WorldSession* session, const std::string& msg,
if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(), GR_RIGHT_GCHATSPEAK)) if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(), GR_RIGHT_GCHATSPEAK))
{ {
WorldPacket data; WorldPacket data;
ChatHandler::FillMessageData(&data, session,CHAT_MSG_GUILD, CHAT_MSG_ADDON, NULL, ObjectGuid(), msg.c_str(), NULL, prefix.c_str()); ChatHandler::BuildChatPacket(data, CHAT_MSG_GUILD, msg.c_str(), LANG_ADDON, CHAT_TAG_NONE, ObjectGuid(), NULL, ObjectGuid(), NULL, NULL, 0, prefix.c_str());
for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{ {
@ -614,20 +614,24 @@ void Guild::BroadcastAddonToGuild(WorldSession* session, const std::string& msg,
void Guild::BroadcastToOfficers(WorldSession* session, const std::string& msg, uint32 language) void Guild::BroadcastToOfficers(WorldSession* session, const std::string& msg, uint32 language)
{ {
if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(), GR_RIGHT_OFFCHATSPEAK)) if (!session)
{ return;
Player* player = session->GetPlayer();
if (!player || !HasRankRight(player->GetRank(), GR_RIGHT_OFFCHATSPEAK))
return;
for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{ {
WorldPacket data; WorldPacket data;
ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, language, msg.c_str()); ChatHandler::BuildChatPacket(data, CHAT_MSG_OFFICER, msg.c_str(), Language(language), player->GetChatTag(), player->GetObjectGuid(), player->GetName());
Player* pl = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first)); Player* pl = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first));
if (pl && pl->GetSession() && HasRankRight(pl->GetRank(), GR_RIGHT_OFFCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetObjectGuid())) if (pl && pl->GetSession() && HasRankRight(pl->GetRank(), GR_RIGHT_OFFCHATLISTEN) && !pl->GetSocial()->HasIgnore(player->GetObjectGuid()))
pl->GetSession()->SendPacket(&data); pl->GetSession()->SendPacket(&data);
} }
} }
}
void Guild::BroadcastAddonToOfficers(WorldSession* session, const std::string& msg, const std::string& prefix) void Guild::BroadcastAddonToOfficers(WorldSession* session, const std::string& msg, const std::string& prefix)
{ {
@ -636,7 +640,7 @@ void Guild::BroadcastAddonToOfficers(WorldSession* session, const std::string& m
for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{ {
WorldPacket data; WorldPacket data;
ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, CHAT_MSG_ADDON, NULL, ObjectGuid(), msg.c_str(), NULL, prefix.c_str()); ChatHandler::BuildChatPacket(data, CHAT_MSG_OFFICER, msg.c_str(), LANG_ADDON, CHAT_TAG_NONE, ObjectGuid(), NULL, ObjectGuid(), NULL, NULL, 0, prefix.c_str());
Player* pl = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first)); Player* pl = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first));

View file

@ -47,11 +47,11 @@ static eConfigFloatValues const qualityToRate[MAX_ITEM_QUALITY] =
LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true); LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true);
LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true); LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true);
LootStore LootTemplates_Fishing("fishing_loot_template", "area id", true); LootStore LootTemplates_Fishing("fishing_loot_template", "area id", true);
LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject lootid", true); LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject Lootid", true);
LootStore LootTemplates_Item("item_loot_template", "item entry with ITEM_FLAG_LOOTABLE", true); LootStore LootTemplates_Item("item_loot_template", "item entry with ITEM_FLAG_LOOTABLE", true);
LootStore LootTemplates_Mail("mail_loot_template", "mail template id", false); LootStore LootTemplates_Mail("mail_loot_template", "mail template id", false);
LootStore LootTemplates_Milling("milling_loot_template", "item entry (herb)", true); LootStore LootTemplates_Milling("milling_loot_template", "item entry (herb)", true);
LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template", "creature pickpocket lootid", true); LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template", "creature pickpocket Lootid", true);
LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry (ore)", true); LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry (ore)", true);
LootStore LootTemplates_Reference("reference_loot_template", "reference id", false); LootStore LootTemplates_Reference("reference_loot_template", "reference id", false);
LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true); LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true);
@ -1271,12 +1271,12 @@ void LoadLootTemplates_Creature()
{ {
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i)) if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
{ {
if (uint32 lootid = cInfo->lootid) if (uint32 Lootid = cInfo->LootId)
{ {
if (ids_set.find(lootid) == ids_set.end()) if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Creature.ReportNotExistedId(lootid); LootTemplates_Creature.ReportNotExistedId(Lootid);
else else
ids_setUsed.insert(lootid); ids_setUsed.insert(Lootid);
} }
} }
} }
@ -1301,12 +1301,12 @@ void LoadLootTemplates_Disenchant()
{ {
if (ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i)) if (ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
{ {
if (uint32 lootid = proto->DisenchantID) if (uint32 Lootid = proto->DisenchantID)
{ {
if (ids_set.find(lootid) == ids_set.end()) if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Disenchant.ReportNotExistedId(lootid); LootTemplates_Disenchant.ReportNotExistedId(Lootid);
else else
ids_setUsed.insert(lootid); ids_setUsed.insert(Lootid);
} }
} }
} }
@ -1344,12 +1344,12 @@ void LoadLootTemplates_Gameobject()
// remove real entries and check existence loot // remove real entries and check existence loot
for (SQLStorageBase::SQLSIterator<GameObjectInfo> itr = sGOStorage.getDataBegin<GameObjectInfo>(); itr < sGOStorage.getDataEnd<GameObjectInfo>(); ++itr) for (SQLStorageBase::SQLSIterator<GameObjectInfo> itr = sGOStorage.getDataBegin<GameObjectInfo>(); itr < sGOStorage.getDataEnd<GameObjectInfo>(); ++itr)
{ {
if (uint32 lootid = itr->GetLootId()) if (uint32 Lootid = itr->GetLootId())
{ {
if (ids_set.find(lootid) == ids_set.end()) if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Gameobject.ReportNotExistedId(lootid); LootTemplates_Gameobject.ReportNotExistedId(Lootid);
else else
ids_setUsed.insert(lootid); ids_setUsed.insert(Lootid);
} }
} }
for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr) for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr)
@ -1419,12 +1419,12 @@ void LoadLootTemplates_Pickpocketing()
{ {
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i)) if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
{ {
if (uint32 lootid = cInfo->pickpocketLootId) if (uint32 Lootid = cInfo->PickpocketLootId)
{ {
if (ids_set.find(lootid) == ids_set.end()) if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Pickpocketing.ReportNotExistedId(lootid); LootTemplates_Pickpocketing.ReportNotExistedId(Lootid);
else else
ids_setUsed.insert(lootid); ids_setUsed.insert(Lootid);
} }
} }
} }
@ -1485,12 +1485,12 @@ void LoadLootTemplates_Skinning()
{ {
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i)) if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
{ {
if (uint32 lootid = cInfo->SkinLootId) if (uint32 Lootid = cInfo->SkinningLootId)
{ {
if (ids_set.find(lootid) == ids_set.end()) if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Skinning.ReportNotExistedId(lootid); LootTemplates_Skinning.ReportNotExistedId(Lootid);
else else
ids_setUsed.insert(lootid); ids_setUsed.insert(Lootid);
} }
} }
} }

View file

@ -49,6 +49,7 @@
#include "TemporarySummon.h" #include "TemporarySummon.h"
#include "movement/packet_builder.h" #include "movement/packet_builder.h"
#include "CreatureLinkingMgr.h" #include "CreatureLinkingMgr.h"
#include "Chat.h"
#ifdef ENABLE_ELUNA #ifdef ENABLE_ELUNA
#include "LuaEngine.h" #include "LuaEngine.h"
#include "ElunaEventMgr.h" #include "ElunaEventMgr.h"
@ -1550,22 +1551,24 @@ bool WorldObject::IsPositionValid() const
void WorldObject::MonsterSay(const char* text, uint32 language, Unit const* target) const void WorldObject::MonsterSay(const char* text, uint32 language, Unit const* target) const
{ {
WorldPacket data(SMSG_MESSAGECHAT, 200); WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), CHAT_MSG_MONSTER_SAY, text, language, GetName(), target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : ""); ChatHandler::BuildChatPacket(data, CHAT_MSG_MONSTER_SAY, text, LANG_UNIVERSAL, CHAT_TAG_NONE, GetObjectGuid(), GetName(),
target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : "");
SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY), true); SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY), true);
} }
void WorldObject::MonsterYell(const char* text, uint32 language, Unit const* target) const void WorldObject::MonsterYell(const char* text, uint32 language, Unit const* target) const
{ {
WorldPacket data(SMSG_MESSAGECHAT, 200); WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), CHAT_MSG_MONSTER_YELL, text, language, GetName(), target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : ""); ChatHandler::BuildChatPacket(data, CHAT_MSG_MONSTER_YELL, text, LANG_UNIVERSAL, CHAT_TAG_NONE, GetObjectGuid(), GetName(),
target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : "");
SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL), true); SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL), true);
} }
void WorldObject::MonsterTextEmote(const char* text, Unit const* target, bool IsBossEmote) const void WorldObject::MonsterTextEmote(const char* text, Unit const* target, bool IsBossEmote) const
{ {
WorldPacket data(SMSG_MESSAGECHAT, 200); WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, text, LANG_UNIVERSAL, ChatHandler::BuildChatPacket(data, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, text, LANG_UNIVERSAL, CHAT_TAG_NONE, GetObjectGuid(), GetName(),
GetName(), target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : ""); target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : "");
SendMessageToSetInRange(&data, sWorld.getConfig(IsBossEmote ? CONFIG_FLOAT_LISTEN_RANGE_YELL : CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), true); SendMessageToSetInRange(&data, sWorld.getConfig(IsBossEmote ? CONFIG_FLOAT_LISTEN_RANGE_YELL : CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), true);
} }
@ -1575,8 +1578,8 @@ void WorldObject::MonsterWhisper(const char* text, Unit const* target, bool IsBo
{ return; } { return; }
WorldPacket data(SMSG_MESSAGECHAT, 200); WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, text, LANG_UNIVERSAL, ChatHandler::BuildChatPacket(data, IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, text, LANG_UNIVERSAL, CHAT_TAG_NONE, GetObjectGuid(), GetName(),
GetName(), target->GetObjectGuid(), target->GetName()); target->GetObjectGuid(), target->GetName());
((Player*)target)->GetSession()->SendPacket(&data); ((Player*)target)->GetSession()->SendPacket(&data);
} }
@ -1585,101 +1588,86 @@ namespace MaNGOS
class MonsterChatBuilder class MonsterChatBuilder
{ {
public: public:
MonsterChatBuilder(WorldObject const& obj, ChatMsg msgtype, int32 textId, uint32 language, Unit const* target) MonsterChatBuilder(WorldObject const& obj, ChatMsg msgtype, MangosStringLocale const* textData, Language language, Unit const* target)
: i_object(obj), i_msgtype(msgtype), i_textId(textId), i_language(language), i_target(target) {} : i_object(obj), i_msgtype(msgtype), i_textData(textData), i_language(language), i_target(target) {}
void operator()(WorldPacket& data, int32 loc_idx) void operator()(WorldPacket& data, int32 loc_idx)
{ {
char const* text = sObjectMgr.GetMangosString(i_textId, loc_idx); char const* text = nullptr;
if ((int32)i_textData->Content.size() > loc_idx + 1 && !i_textData->Content[loc_idx + 1].empty())
text = i_textData->Content[loc_idx + 1].c_str();
else
text = i_textData->Content[0].c_str();
WorldObject::BuildMonsterChat(&data, i_object.GetObjectGuid(), i_msgtype, text, i_language, i_object.GetNameForLocaleIdx(loc_idx), i_target ? i_target->GetObjectGuid() : ObjectGuid(), i_target ? i_target->GetNameForLocaleIdx(loc_idx) : ""); ChatHandler::BuildChatPacket(data, i_msgtype, text, i_language, CHAT_TAG_NONE, i_object.GetObjectGuid(), i_object.GetNameForLocaleIdx(loc_idx),
i_target ? i_target->GetObjectGuid() : ObjectGuid(), i_target ? i_target->GetNameForLocaleIdx(loc_idx) : "");
} }
private: private:
WorldObject const& i_object; WorldObject const& i_object;
ChatMsg i_msgtype; ChatMsg i_msgtype;
int32 i_textId; MangosStringLocale const* i_textData;
uint32 i_language; Language i_language;
Unit const* i_target; Unit const* i_target;
}; };
} // namespace MaNGOS } // namespace MaNGOS
void WorldObject::MonsterSay(int32 textId, uint32 language, Unit const* target) const /// Helper function to create localized around a source
void _DoLocalizedTextAround(WorldObject const* source, MangosStringLocale const* textData, ChatMsg msgtype, Language language, Unit const* target, float range)
{ {
float range = sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY); MaNGOS::MonsterChatBuilder say_build(*source, msgtype, textData, language, target);
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_SAY, textId, language, target);
MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build); MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
MaNGOS::CameraDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(this, range, say_do); MaNGOS::CameraDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(source, range, say_do);
Cell::VisitWorldObjects(this, say_worker, range); Cell::VisitWorldObjects(source, say_worker, range);
} }
void WorldObject::MonsterYell(int32 textId, uint32 language, Unit const* target) const /// Function that sends a text associated to a MangosString
void WorldObject::MonsterText(MangosStringLocale const* textData, Unit const* target) const
{ {
float range = sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL); MANGOS_ASSERT(textData);
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId, language, target);
switch (textData->Type)
{
case CHAT_TYPE_SAY:
_DoLocalizedTextAround(this, textData, CHAT_MSG_MONSTER_SAY, textData->LanguageId, target, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY));
break;
case CHAT_TYPE_YELL:
_DoLocalizedTextAround(this, textData, CHAT_MSG_MONSTER_YELL, textData->LanguageId, target, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL));
break;
case CHAT_TYPE_TEXT_EMOTE:
_DoLocalizedTextAround(this, textData, CHAT_MSG_MONSTER_EMOTE, LANG_UNIVERSAL, target, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE));
break;
case CHAT_TYPE_BOSS_EMOTE:
_DoLocalizedTextAround(this, textData, CHAT_MSG_RAID_BOSS_EMOTE, LANG_UNIVERSAL, target, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL));
break;
case CHAT_TYPE_WHISPER:
{
if (!target || target->GetTypeId() != TYPEID_PLAYER)
return;
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_WHISPER, textData, LANG_UNIVERSAL, target);
MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build); MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
MaNGOS::CameraDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(this, range, say_do); say_do((Player*)target);
Cell::VisitWorldObjects(this, say_worker, range); break;
} }
case CHAT_TYPE_BOSS_WHISPER:
void WorldObject::MonsterYellToZone(int32 textId, uint32 language, Unit const* target) const
{ {
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId, language, target); if (!target || target->GetTypeId() != TYPEID_PLAYER)
return;
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_RAID_BOSS_WHISPER, textData, LANG_UNIVERSAL, target);
MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
say_do((Player*)target);
break;
}
case CHAT_TYPE_ZONE_YELL:
{
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textData, textData->LanguageId, target);
MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build); MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
uint32 zoneid = GetZoneId(); uint32 zoneid = GetZoneId();
Map::PlayerList const& pList = GetMap()->GetPlayers(); Map::PlayerList const& pList = GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
if (itr->getSource()->GetZoneId() == zoneid) if (itr->getSource()->GetZoneId() == zoneid)
say_do(itr->getSource()); say_do(itr->getSource());
break;
} }
void WorldObject::MonsterTextEmote(int32 textId, Unit const* target, bool IsBossEmote) const
{
float range = sWorld.getConfig(IsBossEmote ? CONFIG_FLOAT_LISTEN_RANGE_YELL : CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE);
MaNGOS::MonsterChatBuilder say_build(*this, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, textId, LANG_UNIVERSAL, target);
MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
MaNGOS::CameraDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(this, range, say_do);
Cell::VisitWorldObjects(this, say_worker, range);
}
void WorldObject::MonsterWhisper(int32 textId, Unit const* target, bool IsBossWhisper) const
{
if (!target || target->GetTypeId() != TYPEID_PLAYER)
return;
uint32 loc_idx = ((Player*)target)->GetSession()->GetSessionDbLocaleIndex();
char const* text = sObjectMgr.GetMangosString(textId, loc_idx);
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, text, LANG_UNIVERSAL,
GetNameForLocaleIdx(loc_idx), target->GetObjectGuid(), "");
((Player*)target)->GetSession()->SendPacket(&data);
}
void WorldObject::BuildMonsterChat(WorldPacket* data, ObjectGuid senderGuid, uint8 msgtype, char const* text, uint32 language, char const* name, ObjectGuid targetGuid, char const* targetName)
{
*data << uint8(msgtype);
*data << uint32(language);
*data << ObjectGuid(senderGuid);
*data << uint32(0); // 2.1.0
*data << uint32(strlen(name) + 1);
*data << name;
*data << ObjectGuid(targetGuid); // Unit Target
if (targetGuid && !targetGuid.IsPlayer())
{
*data << uint32(strlen(targetName) + 1); // target name length
*data << targetName; // target name
}
*data << uint32(strlen(text) + 1);
*data << text;
*data << uint8(0); // ChatTag
if (msgtype == CHAT_MSG_RAID_BOSS_EMOTE || msgtype == CHAT_MSG_RAID_BOSS_WHISPER)
{
*data << float(0.0f);
*data << uint8(0);
} }
} }

View file

@ -601,16 +601,13 @@ class WorldObject : public Object
virtual void SendMessageToSetInRange(WorldPacket* data, float dist, bool self) const; virtual void SendMessageToSetInRange(WorldPacket* data, float dist, bool self) const;
void SendMessageToSetExcept(WorldPacket* data, Player const* skipped_receiver) const; void SendMessageToSetExcept(WorldPacket* data, Player const* skipped_receiver) const;
void MonsterSay(const char* text, uint32 language, Unit const* target = NULL) const; void MonsterSay(const char* text, uint32 language, Unit const* target = nullptr) const;
void MonsterYell(const char* text, uint32 language, Unit const* target = NULL) const; void MonsterYell(const char* text, uint32 language, Unit const* target = nullptr) const;
void MonsterTextEmote(const char* text, Unit const* target, bool IsBossEmote = false) const; void MonsterTextEmote(const char* text, Unit const* target, bool IsBossEmote = false) const;
void MonsterWhisper(const char* text, Unit const* target, bool IsBossWhisper = false) const; void MonsterWhisper(const char* text, Unit const* target, bool IsBossWhisper = false) const;
void MonsterSay(int32 textId, uint32 language, Unit const* target = NULL) const; void MonsterText(MangosStringLocale const* textData, Unit const* target) const;
void MonsterYell(int32 textId, uint32 language, Unit const* target = NULL) const;
void MonsterTextEmote(int32 textId, Unit const* target, bool IsBossEmote = false) const;
void MonsterWhisper(int32 textId, Unit const* receiver, bool IsBossWhisper = false) const;
void MonsterYellToZone(int32 textId, uint32 language, Unit const* target) const; void MonsterYellToZone(int32 textId, uint32 language, Unit const* target) const;
static void BuildMonsterChat(WorldPacket* data, ObjectGuid senderGuid, uint8 msgtype, char const* text, uint32 language, char const* name, ObjectGuid targetGuid, char const* targetName);
void PlayDistanceSound(uint32 sound_id, Player const* target = NULL) const; void PlayDistanceSound(uint32 sound_id, Player const* target = NULL) const;
void PlayDirectSound(uint32 sound_id, Player const* target = NULL) const; void PlayDirectSound(uint32 sound_id, Player const* target = NULL) const;

View file

@ -527,38 +527,38 @@ void ObjectMgr::LoadCreatureTemplates()
if (!ok2) if (!ok2)
continue; continue;
if (cInfo->unit_class != difficultyInfo->unit_class) if (cInfo->UnitClass != difficultyInfo->UnitFlags)
{ {
sLog.outErrorDb("Creature (Entry: %u, class %u) has different `unit_class` in difficulty %u mode (Entry: %u, class %u).", sLog.outErrorDb("Creature (Entry: %u, class %u) has different `UnitClass` in difficulty %u mode (Entry: %u, class %u).",
i, cInfo->unit_class, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->unit_class); i, cInfo->UnitClass, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->UnitClass);
continue; continue;
} }
if (cInfo->npcflag != difficultyInfo->npcflag) if (cInfo->NpcFlags != difficultyInfo->NpcFlags)
{ {
sLog.outErrorDb("Creature (Entry: %u) has different `npcflag` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); sLog.outErrorDb("Creature (Entry: %u) has different `NpcFlags` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue; continue;
} }
if (cInfo->trainer_class != difficultyInfo->trainer_class) if (cInfo->TrainerClass != difficultyInfo->TrainerClass)
{ {
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_class` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); sLog.outErrorDb("Creature (Entry: %u) has different `TrainerClass` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue; continue;
} }
if (cInfo->trainer_race != difficultyInfo->trainer_race) if (cInfo->TrainerRace != difficultyInfo->TrainerRace)
{ {
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_race` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); sLog.outErrorDb("Creature (Entry: %u) has different `trainer_race` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue; continue;
} }
if (cInfo->trainer_type != difficultyInfo->trainer_type) if (cInfo->TrainerType != difficultyInfo->TrainerType)
{ {
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_type` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); sLog.outErrorDb("Creature (Entry: %u) has different `TrainerType` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue; continue;
} }
if (cInfo->trainer_spell != difficultyInfo->trainer_spell) if (cInfo->TrainerSpell != difficultyInfo->TrainerSpell)
{ {
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_spell` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); sLog.outErrorDb("Creature (Entry: %u) has different `trainer_spell` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue; continue;
@ -630,56 +630,89 @@ void ObjectMgr::LoadCreatureTemplates()
if (!displayScaleEntry) if (!displayScaleEntry)
sLog.outErrorDb("Creature (Entry: %u) has nonexistent modelid in modelid_1/modelid_2/modelid_3/modelid_4", cInfo->Entry); sLog.outErrorDb("Creature (Entry: %u) has nonexistent modelid in modelid_1/modelid_2/modelid_3/modelid_4", cInfo->Entry);
if (!cInfo->minlevel) if (!cInfo->MinLevel)
{ {
sLog.outErrorDb("Creature (Entry: %u) has invalid minlevel, set to 1", cInfo->Entry); sLog.outErrorDb("Creature (Entry: %u) has invalid minlevel, set to 1", cInfo->Entry);
const_cast<CreatureInfo*>(cInfo)->minlevel = 1; const_cast<CreatureInfo*>(cInfo)->MinLevel = 1;
} }
if (cInfo->minlevel > cInfo->maxlevel) if (cInfo->MinLevel > cInfo->MaxLevel)
{ {
sLog.outErrorDb("Creature (Entry: %u) has invalid maxlevel, set to minlevel", cInfo->Entry); sLog.outErrorDb("Creature (Entry: %u) has invalid maxlevel, set to minlevel", cInfo->Entry);
const_cast<CreatureInfo*>(cInfo)->maxlevel = cInfo->minlevel; const_cast<CreatureInfo*>(cInfo)->MaxLevel = cInfo->MinLevel;
} }
// use below code for 0-checks for unit_class if (cInfo->MinLevel > DEFAULT_MAX_CREATURE_LEVEL)
if (!cInfo->unit_class)
ERROR_DB_STRICT_LOG("Creature (Entry: %u) not has proper unit_class(%u) for creature_template", cInfo->Entry, cInfo->unit_class);
else if (((1 << (cInfo->unit_class - 1)) & CLASSMASK_ALL_CREATURES) == 0)
sLog.outErrorDb("Creature (Entry: %u) has invalid unit_class(%u) for creature_template", cInfo->Entry, cInfo->unit_class);
if (cInfo->dmgschool >= MAX_SPELL_SCHOOL)
{ {
sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`", cInfo->Entry, cInfo->dmgschool); sLog.outErrorDb("Creature (Entry: %u) `MinLevel` exceeds maximum allowed value of '%u'", cInfo->Entry, uint32(DEFAULT_MAX_CREATURE_LEVEL));
const_cast<CreatureInfo*>(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL; const_cast<CreatureInfo*>(cInfo)->MinLevel = uint32(DEFAULT_MAX_CREATURE_LEVEL);
} }
if (cInfo->baseattacktime == 0) if (cInfo->MaxLevel > DEFAULT_MAX_CREATURE_LEVEL)
const_cast<CreatureInfo*>(cInfo)->baseattacktime = BASE_ATTACK_TIME; {
sLog.outErrorDb("Creature (Entry: %u) `MaxLevel` exceeds maximum allowed value of '%u'", cInfo->Entry, uint32(DEFAULT_MAX_CREATURE_LEVEL));
const_cast<CreatureInfo*>(cInfo)->MaxLevel = uint32(DEFAULT_MAX_CREATURE_LEVEL);
}
if (cInfo->rangeattacktime == 0) if (cInfo->Expansion > MAX_EXPANSION)
const_cast<CreatureInfo*>(cInfo)->rangeattacktime = BASE_ATTACK_TIME; {
sLog.outErrorDb("Creature (Entry: %u) `Expansion(%u)` is not correct", cInfo->Entry, uint32(MAX_EXPANSION));
const_cast<CreatureInfo*>(cInfo)->Expansion = -1;
}
if (cInfo->npcflag & UNIT_NPC_FLAG_SPELLCLICK) if (!cInfo->UnitClass || (((1 << (cInfo->UnitClass - 1)) & CLASSMASK_ALL_CREATURES) == 0))
{
ERROR_DB_STRICT_LOG("Creature (Entry: %u) does not have proper `UnitClass` (%u) in creature_template", cInfo->Entry, cInfo->UnitClass);
// Mark NPC as having improper data by his expansion
const_cast<CreatureInfo*>(cInfo)->Expansion = -1;
}
if (!sLog.HasLogFilter(LOG_FILTER_DB_STRICTED_CHECK) && cInfo->Expansion >= 0) // TODO - Remove the DB_STRICTED_CHECK after a while
{
// check if ClassLevel data are available for all possible level of that creature
for (uint32 level = cInfo->MinLevel; level <= cInfo->MaxLevel; ++level)
{
if (!GetCreatureClassLvlStats(level, cInfo->UnitClass, cInfo->Expansion))
{
sLog.outErrorDb("Creature (Entry: %u), level(%u) has no data in `creature_template_classlevelstats`", cInfo->Entry, level);
// Deactivate using ClassLevelStats for this NPC
const_cast<CreatureInfo*>(cInfo)->Expansion = -1;
}
}
}
if (cInfo->DamageSchool >= MAX_SPELL_SCHOOL)
{
sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `DamageSchool`", cInfo->Entry, cInfo->DamageSchool);
const_cast<CreatureInfo*>(cInfo)->DamageSchool = SPELL_SCHOOL_NORMAL;
}
if (cInfo->MeleeAttackPower == 0)
const_cast<CreatureInfo*>(cInfo)->MeleeAttackPower = BASE_ATTACK_TIME;
if (cInfo->RangedAttackPower == 0)
const_cast<CreatureInfo*>(cInfo)->RangedAttackPower = BASE_ATTACK_TIME;
if (cInfo->NpcFlags & UNIT_NPC_FLAG_SPELLCLICK)
{ {
sLog.outDebug("Creature (Entry: %u) has dynamic flag UNIT_NPC_FLAG_SPELLCLICK (%u) set, but it is expected to be set in run-time based at `npc_spellclick_spells` contents.", cInfo->Entry, UNIT_NPC_FLAG_SPELLCLICK); sLog.outDebug("Creature (Entry: %u) has dynamic flag UNIT_NPC_FLAG_SPELLCLICK (%u) set, but it is expected to be set in run-time based at `npc_spellclick_spells` contents.", cInfo->Entry, UNIT_NPC_FLAG_SPELLCLICK);
const_cast<CreatureInfo*>(cInfo)->npcflag &= ~UNIT_NPC_FLAG_SPELLCLICK; const_cast<CreatureInfo*>(cInfo)->NpcFlags &= ~UNIT_NPC_FLAG_SPELLCLICK;
} }
if ((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE) if ((cInfo->NpcFlags & UNIT_NPC_FLAG_TRAINER) && cInfo->TrainerType >= MAX_TRAINER_TYPE)
sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u", cInfo->Entry, cInfo->trainer_type); sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u", cInfo->Entry, cInfo->TrainerType);
if (cInfo->type && !sCreatureTypeStore.LookupEntry(cInfo->type)) if (cInfo->CreatureType && !sCreatureTypeStore.LookupEntry(cInfo->CreatureType))
{ {
sLog.outErrorDb("Creature (Entry: %u) has invalid creature type (%u) in `type`", cInfo->Entry, cInfo->type); sLog.outErrorDb("Creature (Entry: %u) has invalid creature type (%u) in `type`", cInfo->Entry, cInfo->CreatureType);
const_cast<CreatureInfo*>(cInfo)->type = CREATURE_TYPE_HUMANOID; const_cast<CreatureInfo*>(cInfo)->CreatureType = CREATURE_TYPE_HUMANOID;
} }
// must exist or used hidden but used in data horse case // must exist or used hidden but used in data horse case
if (cInfo->family && !sCreatureFamilyStore.LookupEntry(cInfo->family) && cInfo->family != CREATURE_FAMILY_HORSE_CUSTOM) if (cInfo->Family && !sCreatureFamilyStore.LookupEntry(cInfo->Family) && cInfo->Family != CREATURE_FAMILY_HORSE_CUSTOM)
{ {
sLog.outErrorDb("Creature (Entry: %u) has invalid creature family (%u) in `family`", cInfo->Entry, cInfo->family); sLog.outErrorDb("Creature (Entry: %u) has invalid creature family (%u) in `Family`", cInfo->Entry, cInfo->Family);
const_cast<CreatureInfo*>(cInfo)->family = 0; const_cast<CreatureInfo*>(cInfo)->Family = 0;
} }
if (cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE) if (cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE)
@ -716,10 +749,10 @@ void ObjectMgr::LoadCreatureTemplates()
} }
} }
if (cInfo->vendorId > 0) if (cInfo->VendorTemplateId > 0)
{ {
if (!(cInfo->npcflag & UNIT_NPC_FLAG_VENDOR)) if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_VENDOR))
sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with vendor_id %u but not have flag UNIT_NPC_FLAG_VENDOR (%u), vendor items will ignored.", cInfo->Entry, cInfo->vendorId, UNIT_NPC_FLAG_VENDOR); sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with vendor_id %u but not have flag UNIT_NPC_FLAG_VENDOR (%u), vendor items will ignored.", cInfo->Entry, cInfo->VendorTemplateId, UNIT_NPC_FLAG_VENDOR);
} }
/// if not set custom creature Scale then load Scale from CreatureDisplayInfo.dbc /// if not set custom creature Scale then load Scale from CreatureDisplayInfo.dbc
@ -948,6 +981,19 @@ void ObjectMgr::LoadCreatureClassLvlStats()
sLog.outString(">> Loaded %u creature class level stats definitions.", DataCount); sLog.outString(">> Loaded %u creature class level stats definitions.", DataCount);
} }
CreatureClassLvlStats const* ObjectMgr::GetCreatureClassLvlStats(uint32 level, uint32 unitClass, int32 expansion) const
{
if (expansion < 0)
return nullptr;
CreatureClassLvlStats const* cCLS = &m_creatureClassLvlStats[level][classToIndex[unitClass]][expansion];
if (cCLS->BaseHealth != 0 && cCLS->BaseDamage > 0.1f)
return cCLS;
return nullptr;
}
void ObjectMgr::LoadEquipmentTemplates() void ObjectMgr::LoadEquipmentTemplates()
{ {
sEquipmentStorage.Load(); sEquipmentStorage.Load();
@ -1401,30 +1447,30 @@ void ObjectMgr::LoadCreatures()
} }
} }
if (cInfo->RegenHealth && data.curhealth < cInfo->minhealth) if (cInfo->RegenerateStats & REGEN_FLAG_HEALTH && data.curhealth < cInfo->MinLevelHealth)
{ {
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`RegenHealth`=1 and low current health (%u), `creature_template`.`minhealth`=%u.", guid, data.id, data.curhealth, cInfo->minhealth); sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`RegenHealth`=1 and low current health (%u), `creature_template`.`MinLevelHealth`=%u.", guid, data.id, data.curhealth, cInfo->MinLevelHealth);
data.curhealth = cInfo->minhealth; data.curhealth = cInfo->MinLevelHealth;
} }
if (cInfo->ExtraFlags & CREATURE_FLAG_EXTRA_INSTANCE_BIND) if (cInfo->ExtraFlags & CREATURE_EXTRA_FLAG_INSTANCE_BIND)
{ {
if (!mapEntry || !mapEntry->IsDungeon()) if (!mapEntry || !mapEntry->IsDungeon())
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`ExtraFlags` including CREATURE_FLAG_EXTRA_INSTANCE_BIND (%u) but creature are not in instance.", sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`ExtraFlags` including CREATURE_EXTRA_FLAG_INSTANCE_BIND (%u) but creature are not in instance.",
guid, data.id, CREATURE_FLAG_EXTRA_INSTANCE_BIND); guid, data.id, CREATURE_EXTRA_FLAG_INSTANCE_BIND);
} }
if (cInfo->ExtraFlags & CREATURE_FLAG_EXTRA_AGGRO_ZONE) if (cInfo->ExtraFlags & CREATURE_EXTRA_FLAG_AGGRO_ZONE)
{ {
if (!mapEntry || !mapEntry->IsDungeon()) if (!mapEntry || !mapEntry->IsDungeon())
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`ExtraFlags` including CREATURE_FLAG_EXTRA_AGGRO_ZONE (%u) but creature are not in instance.", sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`ExtraFlags` including CREATURE_EXTRA_FLAG_AGGRO_ZONE (%u) but creature are not in instance.",
guid, data.id, CREATURE_FLAG_EXTRA_AGGRO_ZONE); guid, data.id, CREATURE_EXTRA_FLAG_AGGRO_ZONE);
} }
if (data.curmana < cInfo->minmana) if (data.curmana < cInfo->MinLevelMana)
{ {
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`minmana`=%u.", guid, data.id, data.curmana, cInfo->minmana); sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`MinLevelMana`=%u.", guid, data.id, data.curmana, cInfo->MinLevelMana);
data.curmana = cInfo->minmana; data.curmana = cInfo->MinLevelMana;
} }
if (data.spawndist < 0.0f) if (data.spawndist < 0.0f)
@ -6601,7 +6647,7 @@ std::string ObjectMgr::GeneratePetName(uint32 entry)
if (list0.empty() || list1.empty()) if (list0.empty() || list1.empty())
{ {
CreatureInfo const* cinfo = GetCreatureTemplate(entry); CreatureInfo const* cinfo = GetCreatureTemplate(entry);
char const* petname = GetPetName(cinfo->family, sWorld.GetDefaultDbcLocale()); char const* petname = GetPetName(cinfo->Family, sWorld.GetDefaultDbcLocale());
if (!petname) if (!petname)
petname = cinfo->Name; petname = cinfo->Name;
return std::string(petname); return std::string(petname);
@ -7340,7 +7386,7 @@ void ObjectMgr::LoadNPCSpellClickSpells()
mSpellClickInfoMap.insert(SpellClickInfoMap::value_type(npc_entry, info)); mSpellClickInfoMap.insert(SpellClickInfoMap::value_type(npc_entry, info));
// mark creature template as spell clickable // mark creature template as spell clickable
const_cast<CreatureInfo*>(cInfo)->npcflag |= UNIT_NPC_FLAG_SPELLCLICK; const_cast<CreatureInfo*>(cInfo)->NpcFlags |= UNIT_NPC_FLAG_SPELLCLICK;
++count; ++count;
} }
@ -7544,8 +7590,8 @@ void ObjectMgr::LoadCreatureQuestRelations()
CreatureInfo const* cInfo = GetCreatureTemplate(itr->first); CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
if (!cInfo) if (!cInfo)
sLog.outErrorDb("Table `creature_questrelation` have data for nonexistent creature entry (%u) and existing quest %u", itr->first, itr->second); sLog.outErrorDb("Table `creature_questrelation` have data for nonexistent creature entry (%u) and existing quest %u", itr->first, itr->second);
else if (!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER)) else if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_QUESTGIVER))
sLog.outErrorDb("Table `creature_questrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second); sLog.outErrorDb("Table `creature_questrelation` has creature entry (%u) for quest %u, but NpcFlags does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second);
} }
} }
@ -7558,8 +7604,8 @@ void ObjectMgr::LoadCreatureInvolvedRelations()
CreatureInfo const* cInfo = GetCreatureTemplate(itr->first); CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
if (!cInfo) if (!cInfo)
sLog.outErrorDb("Table `creature_involvedrelation` have data for nonexistent creature entry (%u) and existing quest %u", itr->first, itr->second); sLog.outErrorDb("Table `creature_involvedrelation` have data for nonexistent creature entry (%u) and existing quest %u", itr->first, itr->second);
else if (!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER)) else if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_QUESTGIVER))
sLog.outErrorDb("Table `creature_involvedrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second); sLog.outErrorDb("Table `creature_involvedrelation` has creature entry (%u) for quest %u, but NpcFlags does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second);
} }
} }
@ -7999,7 +8045,7 @@ bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min
{ {
data.SoundId = fields[10].GetUInt32(); data.SoundId = fields[10].GetUInt32();
data.Type = fields[11].GetUInt32(); data.Type = fields[11].GetUInt32();
data.LanguageId = (Language)fields[12].GetUInt32(); data.LanguageId = Language(fields[12].GetUInt32());
data.Emote = fields[13].GetUInt32(); data.Emote = fields[13].GetUInt32();
if (data.SoundId && !sSoundEntriesStore.LookupEntry(data.SoundId)) if (data.SoundId && !sSoundEntriesStore.LookupEntry(data.SoundId))
@ -8010,7 +8056,7 @@ bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min
if (!GetLanguageDescByID(data.LanguageId)) if (!GetLanguageDescByID(data.LanguageId))
{ {
_DoStringError(entry, "Entry %i in table `%s` using Language %u but Language does not exist.", entry, table, data.LanguageId); _DoStringError(entry, "Entry %i in table `%s` using Language %u but Language does not exist.", entry, table, uint32(data.LanguageId));
data.LanguageId = LANG_UNIVERSAL; data.LanguageId = LANG_UNIVERSAL;
} }
@ -9237,7 +9283,7 @@ void ObjectMgr::LoadTrainers(char const* tableName, bool isTemplates)
continue; continue;
} }
if (!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER)) if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_TRAINER))
{ {
if (skip_trainers.find(entry) == skip_trainers.end()) if (skip_trainers.find(entry) == skip_trainers.end())
{ {
@ -9247,11 +9293,11 @@ void ObjectMgr::LoadTrainers(char const* tableName, bool isTemplates)
continue; continue;
} }
if (TrainerSpellData const* tSpells = cInfo->trainerId ? GetNpcTrainerTemplateSpells(cInfo->trainerId) : NULL) if (TrainerSpellData const* tSpells = cInfo->TrainerTemplateId ? GetNpcTrainerTemplateSpells(cInfo->TrainerTemplateId) : NULL)
{ {
if (tSpells->spellList.find(spell) != tSpells->spellList.end()) if (tSpells->spellList.find(spell) != tSpells->spellList.end())
{ {
sLog.outErrorDb("Table `%s` (Entry: %u) has spell %u listed in trainer template %u, ignore", tableName, entry, spell, cInfo->trainerId); sLog.outErrorDb("Table `%s` (Entry: %u) has spell %u listed in trainer template %u, ignore", tableName, entry, spell, cInfo->TrainerTemplateId);
continue; continue;
} }
} }
@ -9349,12 +9395,12 @@ void ObjectMgr::LoadTrainerTemplates()
{ {
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i)) if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
{ {
if (cInfo->trainerId) if (cInfo->TrainerTemplateId)
{ {
if (m_mCacheTrainerTemplateSpellMap.find(cInfo->trainerId) != m_mCacheTrainerTemplateSpellMap.end()) if (m_mCacheTrainerTemplateSpellMap.find(cInfo->TrainerTemplateId) != m_mCacheTrainerTemplateSpellMap.end())
trainer_ids.erase(cInfo->trainerId); trainer_ids.erase(cInfo->TrainerTemplateId);
else else
sLog.outErrorDb("Creature (Entry: %u) has trainer_id = %u for nonexistent trainer template", cInfo->Entry, cInfo->trainerId); sLog.outErrorDb("Creature (Entry: %u) has trainer_id = %u for nonexistent trainer template", cInfo->Entry, cInfo->TrainerTemplateId);
} }
} }
} }
@ -9433,12 +9479,12 @@ void ObjectMgr::LoadVendorTemplates()
{ {
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i)) if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
{ {
if (cInfo->vendorId) if (cInfo->VendorTemplateId)
{ {
if (m_mCacheVendorTemplateItemMap.find(cInfo->vendorId) != m_mCacheVendorTemplateItemMap.end()) if (m_mCacheVendorTemplateItemMap.find(cInfo->VendorTemplateId) != m_mCacheVendorTemplateItemMap.end())
vendor_ids.erase(cInfo->vendorId); vendor_ids.erase(cInfo->VendorTemplateId);
else else
sLog.outErrorDb("Creature (Entry: %u) has vendor_id = %u for nonexistent vendor template", cInfo->Entry, cInfo->vendorId); sLog.outErrorDb("Creature (Entry: %u) has vendor_id = %u for nonexistent vendor template", cInfo->Entry, cInfo->VendorTemplateId);
} }
} }
} }
@ -9593,7 +9639,7 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
m_mGossipMenuItemsMap.clear(); m_mGossipMenuItemsMap.clear();
QueryResult* result = WorldDatabase.Query( QueryResult* result = WorldDatabase.Query(
"SELECT menu_id, id, option_icon, option_text, option_id, npc_option_npcflag, " "SELECT menu_id, id, option_icon, option_text, option_id, npc_option_NpcFlags, "
"action_menu_id, action_poi_id, action_script_id, box_coded, box_money, box_text, " "action_menu_id, action_poi_id, action_script_id, box_coded, box_money, box_text, "
"condition_id " "condition_id "
"FROM gossip_menu_option ORDER BY menu_id, id"); "FROM gossip_menu_option ORDER BY menu_id, id");
@ -9654,7 +9700,7 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
gMenuItem.option_icon = fields[2].GetUInt8(); gMenuItem.option_icon = fields[2].GetUInt8();
gMenuItem.option_text = fields[3].GetCppString(); gMenuItem.option_text = fields[3].GetCppString();
gMenuItem.option_id = fields[4].GetUInt32(); gMenuItem.option_id = fields[4].GetUInt32();
gMenuItem.npc_option_npcflag = fields[5].GetUInt32(); gMenuItem.npc_option_NpcFlags = fields[5].GetUInt32();
gMenuItem.action_menu_id = fields[6].GetInt32(); gMenuItem.action_menu_id = fields[6].GetInt32();
gMenuItem.action_poi_id = fields[7].GetUInt32(); gMenuItem.action_poi_id = fields[7].GetUInt32();
gMenuItem.action_script_id = fields[8].GetUInt32(); gMenuItem.action_script_id = fields[8].GetUInt32();
@ -9693,7 +9739,7 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
if (gMenuItem.option_id >= GOSSIP_OPTION_MAX) if (gMenuItem.option_id >= GOSSIP_OPTION_MAX)
sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has unknown option id %u. Option will not be used", gMenuItem.menu_id, gMenuItem.id, gMenuItem.option_id); sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has unknown option id %u. Option will not be used", gMenuItem.menu_id, gMenuItem.id, gMenuItem.option_id);
if (gMenuItem.menu_id && gMenuItem.npc_option_npcflag) if (gMenuItem.menu_id && gMenuItem.npc_option_NpcFlags)
{ {
bool found_menu_uses = false; bool found_menu_uses = false;
bool found_flags_uses = false; bool found_flags_uses = false;
@ -9706,12 +9752,12 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
found_menu_uses = true; found_menu_uses = true;
// some from creatures with gossip menu can use gossip option base at npc_flags // some from creatures with gossip menu can use gossip option base at npc_flags
if (gMenuItem.npc_option_npcflag & cInfo->npcflag) if (gMenuItem.npc_option_NpcFlags & cInfo->NpcFlags)
found_flags_uses = true; found_flags_uses = true;
} }
if (found_menu_uses && !found_flags_uses) if (found_menu_uses && !found_flags_uses)
sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has `npc_option_npcflag` = %u but creatures using this menu does not have corresponding`npcflag`. Option will not accessible in game.", gMenuItem.menu_id, gMenuItem.id, gMenuItem.npc_option_npcflag); sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has `npc_option_NpcFlags` = %u but creatures using this menu does not have corresponding`NpcFlags`. Option will not accessible in game.", gMenuItem.menu_id, gMenuItem.id, gMenuItem.npc_option_NpcFlags);
} }
if (gMenuItem.action_poi_id && !GetPointOfInterest(gMenuItem.action_poi_id)) if (gMenuItem.action_poi_id && !GetPointOfInterest(gMenuItem.action_poi_id))
@ -9820,7 +9866,7 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
return false; return false;
} }
if (!(cInfo->npcflag & UNIT_NPC_FLAG_VENDOR)) if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_VENDOR))
{ {
if (!skip_vendors || skip_vendors->count(vendor_entry) == 0) if (!skip_vendors || skip_vendors->count(vendor_entry) == 0)
{ {
@ -9923,12 +9969,12 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
} }
else else
{ {
if (!cInfo->vendorId) if (!cInfo->VendorTemplateId)
sLog.outErrorDb("Table `%s` has duplicate items %u for %s %u, ignoring", sLog.outErrorDb("Table `%s` has duplicate items %u for %s %u, ignoring",
tableName, item_id, idStr, vendor_entry); tableName, item_id, idStr, vendor_entry);
else else
sLog.outErrorDb("Table `%s` has duplicate items %u for %s %u (or possible in vendor template %u), ignoring", sLog.outErrorDb("Table `%s` has duplicate items %u for %s %u (or possible in vendor template %u), ignoring",
tableName, item_id, idStr, vendor_entry, cInfo->vendorId); tableName, item_id, idStr, vendor_entry, cInfo->VendorTemplateId);
} }
return false; return false;
} }
@ -9974,7 +10020,7 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
return false; return false;
} }
if (!(cInfo->npcflag & UNIT_NPC_FLAG_VENDOR)) if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_VENDOR))
{ {
if (!skip_vendors || skip_vendors->count(vendor_entry) == 0) if (!skip_vendors || skip_vendors->count(vendor_entry) == 0)
{ {
@ -10111,12 +10157,12 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST, item_id, type == VENDOR_ITEM_TYPE_CURRENCY, ExtendedCost); ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST, item_id, type == VENDOR_ITEM_TYPE_CURRENCY, ExtendedCost);
else else
{ {
if (!cInfo->vendorId) if (!cInfo->VendorTemplateId)
sLog.outErrorDb("Table `%s` has duplicate %s %u (with extended cost %u) for %s %u, ignoring", sLog.outErrorDb("Table `%s` has duplicate %s %u (with extended cost %u) for %s %u, ignoring",
tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry); tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry);
else else
sLog.outErrorDb("Table `%s` has duplicate %s %u (with extended cost %u) for %s %u (or possible in vendor template %u), ignoring", sLog.outErrorDb("Table `%s` has duplicate %s %u (with extended cost %u) for %s %u (or possible in vendor template %u), ignoring",
tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry, cInfo->vendorId); tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry, cInfo->VendorTemplateId);
} }
return false; return false;
} }
@ -10366,47 +10412,13 @@ bool DoDisplayText(WorldObject* source, int32 entry, Unit const* target /*=NULL*
} }
} }
switch (data->Type) if ((data->Type == CHAT_TYPE_WHISPER || data->Type == CHAT_TYPE_BOSS_WHISPER) && (!target || target->GetTypeId() != TYPEID_PLAYER))
{
case CHAT_TYPE_SAY:
source->MonsterSay(entry, data->LanguageId, target);
break;
case CHAT_TYPE_YELL:
source->MonsterYell(entry, data->LanguageId, target);
break;
case CHAT_TYPE_TEXT_EMOTE:
source->MonsterTextEmote(entry, target);
break;
case CHAT_TYPE_BOSS_EMOTE:
source->MonsterTextEmote(entry, target, true);
break;
case CHAT_TYPE_WHISPER:
{
if (target && target->GetTypeId() == TYPEID_PLAYER)
source->MonsterWhisper(entry, target);
else
{ {
_DoStringError(entry, "DoDisplayText entry %i cannot whisper without target unit (TYPEID_PLAYER).", entry); _DoStringError(entry, "DoDisplayText entry %i cannot whisper without target unit (TYPEID_PLAYER).", entry);
return false; return false;
} }
break;
}
case CHAT_TYPE_BOSS_WHISPER:
{
if (target && target->GetTypeId() == TYPEID_PLAYER)
source->MonsterWhisper(entry, target, true);
else
{
_DoStringError(entry, "DoDisplayText entry %i cannot whisper without target unit (TYPEID_PLAYER).", entry);
return false;
}
break;
}
case CHAT_TYPE_ZONE_YELL:
source->MonsterYellToZone(entry, data->LanguageId, target);
break;
}
source->MonsterText(data, target);
return true; return true;
} }

View file

@ -132,7 +132,7 @@ typedef UNORDERED_MAP < uint32/*(mapid,spawnMode) pair*/, CellObjectGuidsMap > M
#define MIN_MANGOS_STRING_ID 1 // 'mangos_string' #define MIN_MANGOS_STRING_ID 1 // 'mangos_string'
#define MAX_MANGOS_STRING_ID 2000000000 #define MAX_MANGOS_STRING_ID 2000000000
#define MIN_DB_SCRIPT_STRING_ID MAX_MANGOS_STRING_ID // 'db_script_string' #define MIN_DB_SCRIPT_STRING_ID MAX_MANGOS_STRING_ID // 'db_script_string'
#define MAX_DB_SCRIPT_STRING_ID 2000010000 #define MAX_DB_SCRIPT_STRING_ID 2001000000
#define MIN_CREATURE_AI_TEXT_STRING_ID (-1) // 'creature_ai_texts' #define MIN_CREATURE_AI_TEXT_STRING_ID (-1) // 'creature_ai_texts'
#define MAX_CREATURE_AI_TEXT_STRING_ID (-1000000) #define MAX_CREATURE_AI_TEXT_STRING_ID (-1000000)
// Anything below MAX_CREATURE_AI_TEXT_STRING_ID is handled by the external script lib // Anything below MAX_CREATURE_AI_TEXT_STRING_ID is handled by the external script lib
@ -283,7 +283,7 @@ struct GossipMenuItems
uint8 option_icon; uint8 option_icon;
std::string option_text; std::string option_text;
uint32 option_id; uint32 option_id;
uint32 npc_option_npcflag; uint32 npc_option_NpcFlags;
int32 action_menu_id; int32 action_menu_id;
uint32 action_poi_id; uint32 action_poi_id;
uint32 action_script_id; uint32 action_script_id;
@ -1191,6 +1191,19 @@ class ObjectMgr
QuestRelationsMap& GetCreatureQuestRelationsMap() { return m_CreatureQuestRelations; } QuestRelationsMap& GetCreatureQuestRelationsMap() { return m_CreatureQuestRelations; }
uint32 GetModelForRace(uint32 sourceModelId, uint32 racemask); uint32 GetModelForRace(uint32 sourceModelId, uint32 racemask);
/**
* \brief: Data returned is used to compute health, mana, armor, damage of creatures. May be nullptr.
* \param uint32 level creature level
* \param uint32 unitClass creature class, related to CLASSMASK_ALL_CREATURES
* \param uint32 expansion creature expansion (we could have creature exp = 0 for wotlk as well as exp = 1 or exp = 2)
* \return: CreatureClassLvlStats const* or nullptr
*
* Description: GetCreatureClassLvlStats give fast access to creature stats data.
* FullName: ObjectMgr::GetCreatureClassLvlStats
* Access: public
* Qualifier: const
**/
CreatureClassLvlStats const* GetCreatureClassLvlStats(uint32 level, uint32 unitClass, int32 expansion) const;
void LoadHotfixData(); void LoadHotfixData();
HotfixData const& GetHotfixData() const { return m_hotfixData; } HotfixData const& GetHotfixData() const { return m_hotfixData; }

View file

@ -180,7 +180,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
// reget for sure use real creature info selected for Pet at load/creating // reget for sure use real creature info selected for Pet at load/creating
CreatureInfo const* cinfo = GetCreatureInfo(); CreatureInfo const* cinfo = GetCreatureInfo();
if (cinfo->type == CREATURE_TYPE_CRITTER) if (cinfo->CreatureType == CREATURE_TYPE_CRITTER)
{ {
AIM_Initialize(); AIM_Initialize();
pos.GetMap()->Add((Creature*)this); pos.GetMap()->Add((Creature*)this);
@ -817,7 +817,7 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
return false; return false;
} }
if (cinfo->type == CREATURE_TYPE_CRITTER) if (cinfo->CreatureType == CREATURE_TYPE_CRITTER)
{ {
setPetType(MINI_PET); setPetType(MINI_PET);
return true; return true;
@ -830,12 +830,12 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr.GetXPForPetLevel(creature->getLevel())); SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr.GetXPForPetLevel(creature->getLevel()));
SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family)) if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->Family))
SetName(cFamily->Name[sWorld.GetDefaultDbcLocale()]); SetName(cFamily->Name[sWorld.GetDefaultDbcLocale()]);
else else
SetName(creature->GetNameForLocaleIdx(sObjectMgr.GetDBCLocaleIndex())); SetName(creature->GetNameForLocaleIdx(sObjectMgr.GetDBCLocaleIndex()));
if (cinfo->type == CREATURE_TYPE_BEAST) if (cinfo->CreatureType == CREATURE_TYPE_BEAST)
{ {
SetByteValue(UNIT_FIELD_BYTES_0, 1, CLASS_WARRIOR); SetByteValue(UNIT_FIELD_BYTES_0, 1, CLASS_WARRIOR);
SetByteValue(UNIT_FIELD_BYTES_0, 2, GENDER_NONE); SetByteValue(UNIT_FIELD_BYTES_0, 2, GENDER_NONE);
@ -889,7 +889,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
SetLevel(petlevel); SetLevel(petlevel);
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool)); SetMeleeDamageSchool(SpellSchools(cinfo->DamageSchool));
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50)); SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50));
@ -899,7 +899,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0); SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0);
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family); CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->Family);
if (cFamily && cFamily->minScale > 0.0f && getPetType() == HUNTER_PET) if (cFamily && cFamily->minScale > 0.0f && getPetType() == HUNTER_PET)
{ {
float Scale; float Scale;
@ -919,12 +919,12 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
if (getPetType() != HUNTER_PET) if (getPetType() != HUNTER_PET)
{ {
createResistance[SPELL_SCHOOL_HOLY] = cinfo->resistance1; createResistance[SPELL_SCHOOL_HOLY] = cinfo->ResistanceHoly;
createResistance[SPELL_SCHOOL_FIRE] = cinfo->resistance2; createResistance[SPELL_SCHOOL_FIRE] = cinfo->ResistanceFire;
createResistance[SPELL_SCHOOL_NATURE] = cinfo->resistance3; createResistance[SPELL_SCHOOL_NATURE] = cinfo->ResistanceNature;
createResistance[SPELL_SCHOOL_FROST] = cinfo->resistance4; createResistance[SPELL_SCHOOL_FROST] = cinfo->ResistanceFrost;
createResistance[SPELL_SCHOOL_SHADOW] = cinfo->resistance5; createResistance[SPELL_SCHOOL_SHADOW] = cinfo->ResistanceShadow;
createResistance[SPELL_SCHOOL_ARCANE] = cinfo->resistance6; createResistance[SPELL_SCHOOL_ARCANE] = cinfo->ResistanceArcane;
} }
switch (getPetType()) switch (getPetType())
@ -985,8 +985,8 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
sLog.outErrorDb("Summoned pet (Entry: %u) not have pet stats data in DB", cinfo->Entry); sLog.outErrorDb("Summoned pet (Entry: %u) not have pet stats data in DB", cinfo->Entry);
// remove elite bonuses included in DB values // remove elite bonuses included in DB values
SetCreateHealth(uint32(((float(cinfo->maxhealth) / cinfo->maxlevel) / (1 + 2 * cinfo->Rank)) * petlevel)); SetCreateHealth(uint32(((float(cinfo->MaxLevelHealth) / cinfo->MaxLevel) / (1 + 2 * cinfo->Rank)) * petlevel));
SetCreateMana(uint32(((float(cinfo->maxmana) / cinfo->maxlevel) / (1 + 2 * cinfo->Rank)) * petlevel)); SetCreateMana(uint32(((float(cinfo->MaxLevelMana) / cinfo->MaxLevel) / (1 + 2 * cinfo->Rank)) * petlevel));
SetCreateStat(STAT_STRENGTH, 22); SetCreateStat(STAT_STRENGTH, 22);
SetCreateStat(STAT_AGILITY, 22); SetCreateStat(STAT_AGILITY, 22);
@ -1024,7 +1024,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
sLog.outErrorDb("Hunter pet levelstats missing in DB"); sLog.outErrorDb("Hunter pet levelstats missing in DB");
// remove elite bonuses included in DB values // remove elite bonuses included in DB values
SetCreateHealth(uint32(((float(cinfo->maxhealth) / cinfo->maxlevel) / (1 + 2 * cinfo->Rank)) * petlevel)); SetCreateHealth(uint32(((float(cinfo->MaxLevelHealth) / cinfo->MaxLevel) / (1 + 2 * cinfo->Rank)) * petlevel));
SetCreateStat(STAT_STRENGTH, 22); SetCreateStat(STAT_STRENGTH, 22);
SetCreateStat(STAT_AGILITY, 22); SetCreateStat(STAT_AGILITY, 22);
@ -1074,7 +1074,7 @@ bool Pet::HaveInDiet(ItemPrototype const* item) const
if (!cInfo) if (!cInfo)
return false; return false;
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->family); CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->Family);
if (!cFamily) if (!cFamily)
return false; return false;
@ -1563,7 +1563,7 @@ void Pet::InitLevelupSpellsForLevel()
{ {
uint32 level = getLevel(); uint32 level = getLevel();
if (PetLevelupSpellSet const* levelupSpells = GetCreatureInfo()->family ? sSpellMgr.GetPetLevelupSpellList(GetCreatureInfo()->family) : NULL) if (PetLevelupSpellSet const* levelupSpells = GetCreatureInfo()->Family ? sSpellMgr.GetPetLevelupSpellList(GetCreatureInfo()->Family) : NULL)
{ {
// PetLevelupSpellSet ordered by levels, process in reversed order // PetLevelupSpellSet ordered by levels, process in reversed order
for (PetLevelupSpellSet::const_reverse_iterator itr = levelupSpells->rbegin(); itr != levelupSpells->rend(); ++itr) for (PetLevelupSpellSet::const_reverse_iterator itr = levelupSpells->rbegin(); itr != levelupSpells->rend(); ++itr)
@ -1702,7 +1702,7 @@ bool Pet::resetTalents(bool no_cost)
if (!ci) if (!ci)
return false; return false;
// Check pet talent type // Check pet talent type
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family); CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->Family);
if (!pet_family || pet_family->petTalentType < 0) if (!pet_family || pet_family->petTalentType < 0)
return false; return false;
@ -1961,9 +1961,9 @@ bool Pet::IsPermanentPetFor(Player* owner)
// oddly enough, Mage's Water Elemental is still treated as temporary pet with Glyph of Eternal Water // oddly enough, Mage's Water Elemental is still treated as temporary pet with Glyph of Eternal Water
// i.e. does not unsummon at mounting, gets dismissed at teleport etc. // i.e. does not unsummon at mounting, gets dismissed at teleport etc.
case CLASS_WARLOCK: case CLASS_WARLOCK:
return GetCreatureInfo()->type == CREATURE_TYPE_DEMON; return GetCreatureInfo()->CreatureType == CREATURE_TYPE_DEMON;
case CLASS_DEATH_KNIGHT: case CLASS_DEATH_KNIGHT:
return GetCreatureInfo()->type == CREATURE_TYPE_UNDEAD; return GetCreatureInfo()->CreatureType == CREATURE_TYPE_UNDEAD;
default: default:
return false; return false;
} }
@ -2012,7 +2012,7 @@ void Pet::LearnPetPassives()
if (!cInfo) if (!cInfo)
return; return;
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->family); CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->Family);
if (!cFamily) if (!cFamily)
return; return;

View file

@ -168,7 +168,7 @@ class Pet : public Creature
return m_autospells[pos]; return m_autospells[pos];
} }
bool CanSwim() const override bool CanSwim() const
{ {
Unit const* owner = GetOwner(); Unit const* owner = GetOwner();
if (owner) if (owner)

View file

@ -1526,7 +1526,7 @@ bool Player::BuildEnumData(QueryResult* result, ByteBuffer* data, ByteBuffer* bu
{ {
petDisplayId = fields[17].GetUInt32(); petDisplayId = fields[17].GetUInt32();
petLevel = fields[18].GetUInt32(); petLevel = fields[18].GetUInt32();
petFamily = cInfo->family; petFamily = cInfo->Family;
} }
} }
@ -1644,9 +1644,9 @@ void Player::ToggleDND()
ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND); ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND);
} }
uint8 Player::GetChatTag() const ChatTagFlags Player::GetChatTag() const
{ {
uint8 tag = CHAT_TAG_NONE; ChatTagFlags tag = CHAT_TAG_NONE;
if (isAFK()) if (isAFK())
tag |= CHAT_TAG_AFK; tag |= CHAT_TAG_AFK;
@ -2291,7 +2291,7 @@ void Player::RegenerateHealth(uint32 diff)
ModifyHealth(int32(addvalue)); ModifyHealth(int32(addvalue));
} }
Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask) Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 NpcFlagsmask)
{ {
// some basic checks // some basic checks
if (!guid || !IsInWorld() || IsTaxiFlying()) if (!guid || !IsInWorld() || IsTaxiFlying())
@ -2307,10 +2307,10 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask)
return NULL; return NULL;
// appropriate npc type // appropriate npc type
if (npcflagmask && !unit->HasFlag(UNIT_NPC_FLAGS, npcflagmask)) if (NpcFlagsmask && !unit->HasFlag(UNIT_NPC_FLAGS, NpcFlagsmask))
return NULL; return NULL;
if (npcflagmask == UNIT_NPC_FLAG_STABLEMASTER) if (NpcFlagsmask == UNIT_NPC_FLAG_STABLEMASTER)
{ {
if (getClass() != CLASS_HUNTER) if (getClass() != CLASS_HUNTER)
return NULL; return NULL;
@ -5047,7 +5047,7 @@ void Player::CleanupChannels()
{ {
Channel* ch = *m_channels.begin(); Channel* ch = *m_channels.begin();
m_channels.erase(m_channels.begin()); // remove from player's channel list m_channels.erase(m_channels.begin()); // remove from player's channel list
ch->Leave(GetObjectGuid(), false); // not send to client, not remove from player's channel list ch->Leave(this, false); // not send to client, not remove from player's channel list
if (ChannelMgr* cMgr = channelMgr(GetTeam())) if (ChannelMgr* cMgr = channelMgr(GetTeam()))
cMgr->LeftChannel(ch->GetName()); // deleted channel if empty cMgr->LeftChannel(ch->GetName()); // deleted channel if empty
} }
@ -5091,13 +5091,13 @@ void Player::UpdateLocalChannels(uint32 newZone)
if ((*i) != new_channel) if ((*i) != new_channel)
{ {
new_channel->Join(GetObjectGuid(), ""); // will output Changed Channel: N. Name new_channel->Join(this, ""); // will output Changed Channel: N. Name
// leave old channel // leave old channel
(*i)->Leave(GetObjectGuid(), false); // not send leave channel, it already replaced at client (*i)->Leave(this, false); // not send leave channel, it already replaced at client
std::string name = (*i)->GetName(); // store name, (*i)erase in LeftChannel std::string name = (*i)->GetName(); // store name, (*i)erase in LeftChannel
LeftChannel(*i); // remove from player's channel list LeftChannel(*i); // remove from player's channel list
cMgr->LeftChannel(name); // delete if empty cMgr->LeftChannel(name); // delete if empty // delete if empty
} }
} }
DEBUG_LOG("Player: channels cleaned up!"); DEBUG_LOG("Player: channels cleaned up!");
@ -5109,7 +5109,7 @@ void Player::LeaveLFGChannel()
{ {
if ((*i)->IsLFG()) if ((*i)->IsLFG())
{ {
(*i)->Leave(GetObjectGuid()); (*i)->Leave(this);
break; break;
} }
} }
@ -8120,7 +8120,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
// generate loot only if ready for open and spawned in world // generate loot only if ready for open and spawned in world
if (go->getLootState() == GO_READY && go->isSpawned()) if (go->getLootState() == GO_READY && go->isSpawned())
{ {
uint32 lootid = go->GetGOInfo()->GetLootId(); uint32 Lootid = go->GetGOInfo()->GetLootId();
if ((go->GetEntry() == BG_AV_OBJECTID_MINE_N || go->GetEntry() == BG_AV_OBJECTID_MINE_S)) if ((go->GetEntry() == BG_AV_OBJECTID_MINE_N || go->GetEntry() == BG_AV_OBJECTID_MINE_S))
{ {
if (BattleGround* bg = GetBattleGround()) if (BattleGround* bg = GetBattleGround())
@ -8149,11 +8149,11 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
loot->FillLoot(zone, LootTemplates_Fishing, this, true); loot->FillLoot(zone, LootTemplates_Fishing, this, true);
break; break;
default: default:
if (!lootid) if (!Lootid)
break; break;
DEBUG_LOG(" send normal GO loot"); DEBUG_LOG(" send normal GO loot");
loot->FillLoot(lootid, LootTemplates_Gameobject, this, false); loot->FillLoot(Lootid, LootTemplates_Gameobject, this, false);
loot->generateMoneyLoot(go->GetGOInfo()->MinMoneyLoot, go->GetGOInfo()->MaxMoneyLoot); loot->generateMoneyLoot(go->GetGOInfo()->MinMoneyLoot, go->GetGOInfo()->MaxMoneyLoot);
if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules) if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules)
@ -8313,8 +8313,8 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
creature->lootForPickPocketed = true; creature->lootForPickPocketed = true;
loot->clear(); loot->clear();
if (uint32 lootid = creature->GetCreatureInfo()->pickpocketLootId) if (uint32 Lootid = creature->GetCreatureInfo()->PickpocketLootId)
loot->FillLoot(lootid, LootTemplates_Pickpocketing, this, false); loot->FillLoot(Lootid, LootTemplates_Pickpocketing, this, false);
// Generate extra money for pick pocket loot // Generate extra money for pick pocket loot
const uint32 a = urand(0, creature->getLevel() / 2); const uint32 a = urand(0, creature->getLevel() / 2);
@ -8344,10 +8344,10 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
creature->lootForBody = true; creature->lootForBody = true;
loot->clear(); loot->clear();
if (uint32 lootid = creature->GetCreatureInfo()->lootid) if (uint32 Lootid = creature->GetCreatureInfo()->LootId)
loot->FillLoot(lootid, LootTemplates_Creature, recipient, false); loot->FillLoot(Lootid, LootTemplates_Creature, recipient, false);
loot->generateMoneyLoot(creature->GetCreatureInfo()->mingold, creature->GetCreatureInfo()->maxgold); loot->generateMoneyLoot(creature->GetCreatureInfo()->MinLootGold, creature->GetCreatureInfo()->MaxLootGold);
if (Group* group = creature->GetGroupLootRecipient()) if (Group* group = creature->GetGroupLootRecipient())
{ {
@ -8378,7 +8378,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
{ {
creature->lootForSkin = true; creature->lootForSkin = true;
loot->clear(); loot->clear();
loot->FillLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, this, false); loot->FillLoot(creature->GetCreatureInfo()->SkinningLootId, LootTemplates_Skinning, this, false);
// let reopen skinning loot if will closed. // let reopen skinning loot if will closed.
if (!loot->empty()) if (!loot->empty())
@ -8474,302 +8474,6 @@ void Player::SendUpdateWorldState(uint32 Field, uint32 Value)
GetSession()->SendPacket(&data); GetSession()->SendPacket(&data);
} }
static WorldStatePair AV_world_states[] =
{
{ 0x7ae, 0x1 }, // 1966 7 snowfall n
{ 0x532, 0x1 }, // 1330 8 frostwolfhut hc
{ 0x531, 0x0 }, // 1329 9 frostwolfhut ac
{ 0x52e, 0x0 }, // 1326 10 stormpike firstaid a_a
{ 0x571, 0x0 }, // 1393 11 east frostwolf tower horde assaulted -unused
{ 0x570, 0x0 }, // 1392 12 west frostwolf tower horde assaulted - unused
{ 0x567, 0x1 }, // 1383 13 frostwolfe c
{ 0x566, 0x1 }, // 1382 14 frostwolfw c
{ 0x550, 0x1 }, // 1360 15 irondeep (N) ally
{ 0x544, 0x0 }, // 1348 16 ice grave a_a
{ 0x536, 0x0 }, // 1334 17 stormpike grave h_c
{ 0x535, 0x1 }, // 1333 18 stormpike grave a_c
{ 0x518, 0x0 }, // 1304 19 stoneheart grave a_a
{ 0x517, 0x0 }, // 1303 20 stoneheart grave h_a
{ 0x574, 0x0 }, // 1396 21 unk
{ 0x573, 0x0 }, // 1395 22 iceblood tower horde assaulted -unused
{ 0x572, 0x0 }, // 1394 23 towerpoint horde assaulted - unused
{ 0x56f, 0x0 }, // 1391 24 unk
{ 0x56e, 0x0 }, // 1390 25 iceblood a
{ 0x56d, 0x0 }, // 1389 26 towerp a
{ 0x56c, 0x0 }, // 1388 27 frostwolfe a
{ 0x56b, 0x0 }, // 1387 28 froswolfw a
{ 0x56a, 0x1 }, // 1386 29 unk
{ 0x569, 0x1 }, // 1385 30 iceblood c
{ 0x568, 0x1 }, // 1384 31 towerp c
{ 0x565, 0x0 }, // 1381 32 stoneh tower a
{ 0x564, 0x0 }, // 1380 33 icewing tower a
{ 0x563, 0x0 }, // 1379 34 dunn a
{ 0x562, 0x0 }, // 1378 35 duns a
{ 0x561, 0x0 }, // 1377 36 stoneheart bunker alliance assaulted - unused
{ 0x560, 0x0 }, // 1376 37 icewing bunker alliance assaulted - unused
{ 0x55f, 0x0 }, // 1375 38 dunbaldar south alliance assaulted - unused
{ 0x55e, 0x0 }, // 1374 39 dunbaldar north alliance assaulted - unused
{ 0x55d, 0x0 }, // 1373 40 stone tower d
{ 0x3c6, 0x0 }, // 966 41 unk
{ 0x3c4, 0x0 }, // 964 42 unk
{ 0x3c2, 0x0 }, // 962 43 unk
{ 0x516, 0x1 }, // 1302 44 stoneheart grave a_c
{ 0x515, 0x0 }, // 1301 45 stonheart grave h_c
{ 0x3b6, 0x0 }, // 950 46 unk
{ 0x55c, 0x0 }, // 1372 47 icewing tower d
{ 0x55b, 0x0 }, // 1371 48 dunn d
{ 0x55a, 0x0 }, // 1370 49 duns d
{ 0x559, 0x0 }, // 1369 50 unk
{ 0x558, 0x0 }, // 1368 51 iceblood d
{ 0x557, 0x0 }, // 1367 52 towerp d
{ 0x556, 0x0 }, // 1366 53 frostwolfe d
{ 0x555, 0x0 }, // 1365 54 frostwolfw d
{ 0x554, 0x1 }, // 1364 55 stoneh tower c
{ 0x553, 0x1 }, // 1363 56 icewing tower c
{ 0x552, 0x1 }, // 1362 57 dunn c
{ 0x551, 0x1 }, // 1361 58 duns c
{ 0x54f, 0x0 }, // 1359 59 irondeep (N) horde
{ 0x54e, 0x0 }, // 1358 60 irondeep (N) ally
{ 0x54d, 0x1 }, // 1357 61 mine (S) neutral
{ 0x54c, 0x0 }, // 1356 62 mine (S) horde
{ 0x54b, 0x0 }, // 1355 63 mine (S) ally
{ 0x545, 0x0 }, // 1349 64 iceblood h_a
{ 0x543, 0x1 }, // 1347 65 iceblod h_c
{ 0x542, 0x0 }, // 1346 66 iceblood a_c
{ 0x540, 0x0 }, // 1344 67 snowfall h_a
{ 0x53f, 0x0 }, // 1343 68 snowfall a_a
{ 0x53e, 0x0 }, // 1342 69 snowfall h_c
{ 0x53d, 0x0 }, // 1341 70 snowfall a_c
{ 0x53c, 0x0 }, // 1340 71 frostwolf g h_a
{ 0x53b, 0x0 }, // 1339 72 frostwolf g a_a
{ 0x53a, 0x1 }, // 1338 73 frostwolf g h_c
{ 0x539, 0x0 }, // l33t 74 frostwolf g a_c
{ 0x538, 0x0 }, // 1336 75 stormpike grave h_a
{ 0x537, 0x0 }, // 1335 76 stormpike grave a_a
{ 0x534, 0x0 }, // 1332 77 frostwolf hut h_a
{ 0x533, 0x0 }, // 1331 78 frostwolf hut a_a
{ 0x530, 0x0 }, // 1328 79 stormpike first aid h_a
{ 0x52f, 0x0 }, // 1327 80 stormpike first aid h_c
{ 0x52d, 0x1 }, // 1325 81 stormpike first aid a_c
{ 0x0, 0x0 }
};
static WorldStatePair WS_world_states[] =
{
{ 0x62d, 0x0 }, // 1581 7 alliance flag captures
{ 0x62e, 0x0 }, // 1582 8 horde flag captures
{ 0x609, 0x0 }, // 1545 9 unk, set to 1 on alliance flag pickup...
{ 0x60a, 0x0 }, // 1546 10 unk, set to 1 on horde flag pickup, after drop it's -1
{ 0x60b, 0x2 }, // 1547 11 unk
{ 0x641, 0x3 }, // 1601 12 unk (max flag captures?)
{ 0x922, 0x1 }, // 2338 13 horde (0 - hide, 1 - flag ok, 2 - flag picked up (flashing), 3 - flag picked up (not flashing)
{ 0x923, 0x1 }, // 2339 14 alliance (0 - hide, 1 - flag ok, 2 - flag picked up (flashing), 3 - flag picked up (not flashing)
{ 0x1097, 0x1 }, // 4247 15 show time limit?
{ 0x1098, 0x19 }, // 4248 16 time remaining in minutes
{ 0x0, 0x0 }
};
static WorldStatePair AB_world_states[] =
{
{ 0x6e7, 0x0 }, // 1767 7 stables alliance
{ 0x6e8, 0x0 }, // 1768 8 stables horde
{ 0x6e9, 0x0 }, // 1769 9 unk, ST?
{ 0x6ea, 0x0 }, // 1770 10 stables (show/hide)
{ 0x6ec, 0x0 }, // 1772 11 farm (0 - horde controlled, 1 - alliance controlled)
{ 0x6ed, 0x0 }, // 1773 12 farm (show/hide)
{ 0x6ee, 0x0 }, // 1774 13 farm color
{ 0x6ef, 0x0 }, // 1775 14 gold mine color, may be FM?
{ 0x6f0, 0x0 }, // 1776 15 alliance resources
{ 0x6f1, 0x0 }, // 1777 16 horde resources
{ 0x6f2, 0x0 }, // 1778 17 horde bases
{ 0x6f3, 0x0 }, // 1779 18 alliance bases
{ 0x6f4, 0x7d0 }, // 1780 19 max resources (2000)
{ 0x6f6, 0x0 }, // 1782 20 blacksmith color
{ 0x6f7, 0x0 }, // 1783 21 blacksmith (show/hide)
{ 0x6f8, 0x0 }, // 1784 22 unk, bs?
{ 0x6f9, 0x0 }, // 1785 23 unk, bs?
{ 0x6fb, 0x0 }, // 1787 24 gold mine (0 - horde contr, 1 - alliance contr)
{ 0x6fc, 0x0 }, // 1788 25 gold mine (0 - conflict, 1 - horde)
{ 0x6fd, 0x0 }, // 1789 26 gold mine (1 - show/0 - hide)
{ 0x6fe, 0x0 }, // 1790 27 gold mine color
{ 0x700, 0x0 }, // 1792 28 gold mine color, wtf?, may be LM?
{ 0x701, 0x0 }, // 1793 29 lumber mill color (0 - conflict, 1 - horde contr)
{ 0x702, 0x0 }, // 1794 30 lumber mill (show/hide)
{ 0x703, 0x0 }, // 1795 31 lumber mill color color
{ 0x732, 0x1 }, // 1842 32 stables (1 - uncontrolled)
{ 0x733, 0x1 }, // 1843 33 gold mine (1 - uncontrolled)
{ 0x734, 0x1 }, // 1844 34 lumber mill (1 - uncontrolled)
{ 0x735, 0x1 }, // 1845 35 farm (1 - uncontrolled)
{ 0x736, 0x1 }, // 1846 36 blacksmith (1 - uncontrolled)
{ 0x745, 0x2 }, // 1861 37 unk
{ 0x7a3, 0x708 }, // 1955 38 warning limit (1800)
{ 0x0, 0x0 }
};
static WorldStatePair EY_world_states[] =
{
{ 2753, 0 }, // WORLD_STATE_EY_TOWER_COUNT_HORDE
{ 2752, 0 }, // WORLD_STATE_EY_TOWER_COUNT_ALLIANCE
{ 2733, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_DRAENEI_RUINS_HORDE
{ 2732, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_DRAENEI_RUINS_ALLIANCE
{ 2731, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_DRAENEI_RUINS_NEUTRAL
{ 2730, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_MAGE_TOWER_ALLIANCE
{ 2729, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_MAGE_TOWER_HORDE
{ 2728, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_MAGE_TOWER_NEUTRAL
{ 2727, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_FEL_REAVER_HORDE
{ 2726, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_FEL_REAVER_ALLIANCE
{ 2725, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_FEL_REAVER_NEUTRAL
{ 2724, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_BLOOD_ELF_HORDE
{ 2723, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_BLOOD_ELF_ALLIANCE
{ 2722, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_BLOOD_ELF_NEUTRAL
{ 2757, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_NETHERSTORM_FLAG_READY
{ 2770, 1 }, // WORLD_STATE_EY_NETHERSTORM_FLAG_STATE_HORDE
{ 2769, 1 }, // WORLD_STATE_EY_NETHERSTORM_FLAG_STATE_ALLIANCE
{ 2750, 0 }, // WORLD_STATE_EY_RESOURCES_HORDE
{ 2749, 0 }, // WORLD_STATE_EY_RESOURCES_ALLIANCE
{ 2565, 0x8e }, // global unk -- TODO: move to global world state
{ 3085, 0x17b } // global unk -- TODO: move to global world state
};
static WorldStatePair SI_world_states[] = // Silithus
{
{ 2313, 0 }, // WORLD_STATE_SI_GATHERED_A
{ 2314, 0 }, // WORLD_STATE_SI_GATHERED_H
{ 2317, 0 } // WORLD_STATE_SI_SILITHYST_MAX
};
static WorldStatePair EP_world_states[] = // Eastern Plaguelands
{
{ 2327, 0 }, // WORLD_STATE_EP_TOWER_COUNT_ALLIANCE
{ 2328, 0 }, // WORLD_STATE_EP_TOWER_COUNT_HORDE
{ 2355, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_NEUTRAL
{ 2374, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_CONTEST_ALLIANCE
{ 2375, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_CONTEST_HORDE
{ 2376, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_PROGRESS_ALLIANCE
{ 2377, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_PROGRESS_HORDE
{ 2378, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_ALLIANCE
{ 2379, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_HORDE
{ 2354, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_ALLIANCE
{ 2356, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_HORDE
{ 2357, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_PROGRESS_ALLIANCE
{ 2358, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_PROGRESS_HORDE
{ 2359, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_CONTEST_ALLIANCE
{ 2360, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_CONTEST_HORDE
{ 2361, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_NEUTRAL
{ 2352, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_NEUTRAL
{ 2362, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_CONTEST_ALLIANCE
{ 2363, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_CONTEST_HORDE
{ 2364, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_PROGRESS_ALLIANCE
{ 2365, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_PROGRESS_HORDE
{ 2372, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_ALLIANCE
{ 2373, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_HORDE
{ 2353, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_NEUTRAL
{ 2366, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_CONTEST_ALLIANCE
{ 2367, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_CONTEST_HORDE - not in dbc! sent for consistency's sake, and to match field count
{ 2368, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_PROGRESS_ALLIANCE
{ 2369, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_PROGRESS_HORDE
{ 2370, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_ALLIANCE
{ 2371, WORLD_STATE_REMOVE } // WORLD_STATE_EP_PLAGUEWOOD_HORDE
};
static WorldStatePair HP_world_states[] = // Hellfire Peninsula
{
{ 2490, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_TOWER_DISPLAY_A
{ 2489, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_TOWER_DISPLAY_H
{ 2485, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_BROKEN_HILL_NEUTRAL
{ 2484, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_BROKEN_HILL_HORDE
{ 2483, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_BROKEN_HILL_ALLIANCE
{ 2482, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_OVERLOOK_NEUTRAL
{ 2481, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_OVERLOOK_HORDE
{ 2480, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_OVERLOOK_ALLIANCE
{ 2478, 0 }, // WORLD_STATE_HP_TOWER_COUNT_HORDE
{ 2476, 0 }, // WORLD_STATE_HP_TOWER_COUNT_ALLIANCE
{ 2472, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_STADIUM_NEUTRAL
{ 2471, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_STADIUM_ALLIANCE
{ 2470, WORLD_STATE_REMOVE } // WORLD_STATE_HP_STADIUM_HORDE
};
static WorldStatePair TF_world_states[] = // Terokkar Forest
{
{ 2622, 0 }, // WORLD_STATE_TF_TOWER_COUNT_H
{ 2621, 0 }, // WORLD_STATE_TF_TOWER_COUNT_A
{ 2620, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_TOWERS_CONTROLLED
{ 2695, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_EAST_TOWER_HORDE
{ 2694, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_EAST_TOWER_ALLIANCE
{ 2693, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_TOWER_NEUTRAL
{ 2692, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_TOWER_HORDE
{ 2691, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_TOWER_ALLIANCE
{ 2690, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_EAST_TOWER_NEUTRAL
{ 2689, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_EAST_TOWER_HORDE
{ 2688, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_EAST_TOWER_ALLIANCE
{ 2686, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_NORTH_TOWER_NEUTRAL
{ 2685, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_NORTH_TOWER_HORDE
{ 2684, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_NORTH_TOWER_ALLIANCE
{ 2683, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_WEST_TOWER_ALLIANCE
{ 2682, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_WEST_TOWER_HORDE
{ 2681, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_WEST_TOWER_NEUTRAL
{ 2512, 0 }, // WORLD_STATE_TF_TIME_MIN_FIRST_DIGIT
{ 2510, 0 }, // WORLD_STATE_TF_TIME_MIN_SECOND_DIGIT
{ 2509, 0 }, // WORLD_STATE_TF_TIME_HOURS
{ 2508, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_LOCKED_NEUTRAL
{ 2696, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_EAST_TOWER_NEUTRAL
{ 2768, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_LOCKED_HORDE
{ 2767, WORLD_STATE_REMOVE } // WORLD_STATE_TF_LOCKED_ALLIANCE
};
static WorldStatePair ZM_world_states[] = // Zangarmarsh
{
{ 2653, 0x1 }, // WORLD_STATE_ZM_UNK
{ 2652, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_NEUTRAL
{ 2651, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_HORDE
{ 2650, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_ALLIANCE
{ 2649, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_GRAVEYARD_HORDE
{ 2648, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_GRAVEYARD_ALLIANCE
{ 2647, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_GRAVEYARD_NEUTRAL
{ 2646, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_NEUTRAL
{ 2645, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_HORDE
{ 2644, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_ALLIANCE
{ 2560, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_UI_NEUTRAL
{ 2559, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_UI_HORDE
{ 2558, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_UI_ALLIANCE
{ 2557, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_UI_NEUTRAL
{ 2556, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_UI_HORDE
{ 2555, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_UI_ALLIANCE
{ 2658, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_FLAG_READY_HORDE
{ 2657, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_FLAG_NOT_READY_HORDE
{ 2656, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_FLAG_NOT_READY_ALLIANCE
{ 2655, WORLD_STATE_REMOVE } // WORLD_STATE_ZM_FLAG_READY_ALLIANCE
};
static WorldStatePair NA_world_states[] =
{
{ 2503, 0 }, // WORLD_STATE_NA_GUARDS_HORDE
{ 2502, 0 }, // WORLD_STATE_NA_GUARDS_ALLIANCE
{ 2493, 0 }, // WORLD_STATE_NA_GUARDS_MAX
{ 2491, 0 }, // WORLD_STATE_NA_GUARDS_LEFT
{ 2762, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_NORTH_NEUTRAL_H
{ 2662, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_NORTH_NEUTRAL_A
{ 2663, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_NORTH_H
{ 2664, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_NORTH_A
{ 2760, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_SOUTH_NEUTRAL_H
{ 2670, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_SOUTH_NEUTRAL_A
{ 2668, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_SOUTH_H
{ 2669, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_SOUTH_A
{ 2761, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_WEST_NEUTRAL_H
{ 2667, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_WEST_NEUTRAL_A
{ 2665, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_WEST_H
{ 2666, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_WEST_A
{ 2763, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_EAST_NEUTRAL_H
{ 2659, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_EAST_NEUTRAL_A
{ 2660, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_EAST_H
{ 2661, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_EAST_A
{ 2671, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_HALAA_NEUTRAL
{ 2676, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_HALAA_NEUTRAL_A
{ 2677, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_HALAA_NEUTRAL_H
{ 2672, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_HALAA_HORDE
{ 2673, WORLD_STATE_REMOVE } // WORLD_STATE_NA_HALAA_ALLIANCE
};
void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
{ {
// data depends on zoneid/mapid... // data depends on zoneid/mapid...
@ -8787,136 +8491,53 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
size_t count_pos = data.wpos(); size_t count_pos = data.wpos();
data << uint16(0); // count of uint64 blocks, placeholder data << uint16(0); // count of uint64 blocks, placeholder
// common fields // Current arena season
FillInitialWorldState(data, count, 0x8d8, 0x0); // 2264 1
FillInitialWorldState(data, count, 0x8d7, 0x0); // 2263 2
FillInitialWorldState(data, count, 0x8d6, 0x0); // 2262 3
FillInitialWorldState(data, count, 0x8d5, 0x0); // 2261 4
FillInitialWorldState(data, count, 0x8d4, 0x0); // 2260 5
FillInitialWorldState(data, count, 0x8d3, 0x0); // 2259 6
// 3191 7 Current arena season
FillInitialWorldState(data, count, 0xC77, sWorld.getConfig(CONFIG_UINT32_ARENA_SEASON_ID)); FillInitialWorldState(data, count, 0xC77, sWorld.getConfig(CONFIG_UINT32_ARENA_SEASON_ID));
// 3901 8 Previous arena season // Previous arena season
FillInitialWorldState(data, count, 0xF3D, sWorld.getConfig(CONFIG_UINT32_ARENA_SEASON_PREVIOUS_ID)); FillInitialWorldState(data, count, 0xF3D, sWorld.getConfig(CONFIG_UINT32_ARENA_SEASON_PREVIOUS_ID));
FillInitialWorldState(data, count, 0xED9, 1); // 3801 9 0 - Battle for Wintergrasp in progress, 1 - otherwise // 0 - Battle for Wintergrasp in progress, 1 - otherwise
// 4354 10 Time when next Battle for Wintergrasp starts FillInitialWorldState(data, count, 0xED9, 1);
FillInitialWorldState(data, count, 0x1102, uint32(time(NULL) + 9000)); // Time when next Battle for Wintergrasp starts
FillInitialWorldState(data, count, 0x1102, uint32(time(nullptr) + 9000));
if (mapid == 530) // Outland
{
FillInitialWorldState(data, count, 0x9bf, 0x0); // 2495
FillInitialWorldState(data, count, 0x9bd, 0xF); // 2493
FillInitialWorldState(data, count, 0x9bb, 0xF); // 2491
}
switch (zoneid) switch (zoneid)
{ {
case 1: // Dun Morogh
case 11: // Wetlands
case 12: // Elwynn Forest
case 38: // Loch Modan
case 40: // Westfall
case 51: // Searing Gorge
case 1519: // Stormwind City
case 1537: // Ironforge
case 2257: // Deeprun Tram
case 3703: // Shattrath City
break;
case 139: // Eastern Plaguelands case 139: // Eastern Plaguelands
if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid))
outdoorPvP->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, EP_world_states);
break;
case 1377: // Silithus case 1377: // Silithus
case 3483: // Hellfire Peninsula
case 3518: // Nagrand
case 3519: // Terokkar Forest
case 3521: // Zangarmarsh
if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid)) if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid))
outdoorPvP->FillInitialWorldStates(data, count); outdoorPvP->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, SI_world_states);
break; break;
case 2597: // AV case 2597: // AV
if (bg && bg->GetTypeID() == BATTLEGROUND_AV) if (bg && bg->GetTypeID() == BATTLEGROUND_AV)
bg->FillInitialWorldStates(data, count); bg->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, AV_world_states);
break; break;
case 3277: // WS case 3277: // WS
if (bg && bg->GetTypeID() == BATTLEGROUND_WS) if (bg && bg->GetTypeID() == BATTLEGROUND_WS)
bg->FillInitialWorldStates(data, count); bg->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, WS_world_states);
break; break;
case 3358: // AB case 3358: // AB
if (bg && bg->GetTypeID() == BATTLEGROUND_AB) if (bg && bg->GetTypeID() == BATTLEGROUND_AB)
bg->FillInitialWorldStates(data, count); bg->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, AB_world_states);
break; break;
case 3820: // EY case 3820: // EY
if (bg && bg->GetTypeID() == BATTLEGROUND_EY) if (bg && bg->GetTypeID() == BATTLEGROUND_EY)
bg->FillInitialWorldStates(data, count); bg->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, EY_world_states);
break;
case 3483: // Hellfire Peninsula
if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid))
outdoorPvP->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, HP_world_states);
break;
case 3518: // Nagrand
if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid))
outdoorPvP->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, NA_world_states);
break;
case 3519: // Terokkar Forest
if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid))
outdoorPvP->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, TF_world_states);
break;
case 3521: // Zangarmarsh
if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid))
outdoorPvP->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, ZM_world_states);
break; break;
case 3698: // Nagrand Arena case 3698: // Nagrand Arena
if (bg && bg->GetTypeID() == BATTLEGROUND_NA) if (bg && bg->GetTypeID() == BATTLEGROUND_NA)
bg->FillInitialWorldStates(data, count); bg->FillInitialWorldStates(data, count);
else
{
FillInitialWorldState(data, count, 0xa0f, 0x0); // 2575 7
FillInitialWorldState(data, count, 0xa10, 0x0); // 2576 8
FillInitialWorldState(data, count, 0xa11, 0x0); // 2577 9 show
}
break; break;
case 3702: // Blade's Edge Arena case 3702: // Blade's Edge Arena
if (bg && bg->GetTypeID() == BATTLEGROUND_BE) if (bg && bg->GetTypeID() == BATTLEGROUND_BE)
bg->FillInitialWorldStates(data, count); bg->FillInitialWorldStates(data, count);
else
{
FillInitialWorldState(data, count, 0x9f0, 0x0); // 2544 7 gold
FillInitialWorldState(data, count, 0x9f1, 0x0); // 2545 8 green
FillInitialWorldState(data, count, 0x9f3, 0x0); // 2547 9 show
}
break; break;
case 3968: // Ruins of Lordaeron case 3968: // Ruins of Lordaeron
if (bg && bg->GetTypeID() == BATTLEGROUND_RL) if (bg && bg->GetTypeID() == BATTLEGROUND_RL)
bg->FillInitialWorldStates(data, count); bg->FillInitialWorldStates(data, count);
else
{
FillInitialWorldState(data, count, 0xbb8, 0x0); // 3000 7 gold
FillInitialWorldState(data, count, 0xbb9, 0x0); // 3001 8 green
FillInitialWorldState(data, count, 0xbba, 0x0); // 3002 9 show
}
break;
default:
FillInitialWorldState(data, count, 0x914, 0x0); // 2324 7
FillInitialWorldState(data, count, 0x913, 0x0); // 2323 8
FillInitialWorldState(data, count, 0x912, 0x0); // 2322 9
FillInitialWorldState(data, count, 0x915, 0x0); // 2325 10
break; break;
} }
@ -13093,9 +12714,9 @@ void Player::PrepareGossipMenu(WorldObject* pSource, uint32 menuId)
{ {
Creature* pCreature = (Creature*)pSource; Creature* pCreature = (Creature*)pSource;
uint32 npcflags = pCreature->GetUInt32Value(UNIT_NPC_FLAGS); uint32 NpcFlagss = pCreature->GetUInt32Value(UNIT_NPC_FLAGS);
if (!(itr->second.npc_option_npcflag & npcflags)) if (!(itr->second.npc_option_NpcFlags & NpcFlagss))
continue; continue;
switch (itr->second.option_id) switch (itr->second.option_id)
@ -13126,7 +12747,7 @@ void Player::PrepareGossipMenu(WorldObject* pSource, uint32 menuId)
case GOSSIP_OPTION_TRAINER: case GOSSIP_OPTION_TRAINER:
// pet trainers not have spells in fact now // pet trainers not have spells in fact now
/* FIXME: gossip menu with single unlearn pet talents option not show by some reason /* FIXME: gossip menu with single unlearn pet talents option not show by some reason
if (pCreature->GetCreatureInfo()->trainer_type == TRAINER_TYPE_PETS) if (pCreature->GetCreatureInfo()->TrainerType == TRAINER_TYPE_PETS)
hasMenuItem = false; hasMenuItem = false;
else */ else */
if (!pCreature->IsTrainerOf(this, false)) if (!pCreature->IsTrainerOf(this, false))
@ -13137,7 +12758,7 @@ void Player::PrepareGossipMenu(WorldObject* pSource, uint32 menuId)
hasMenuItem = false; hasMenuItem = false;
break; break;
case GOSSIP_OPTION_UNLEARNPETSKILLS: case GOSSIP_OPTION_UNLEARNPETSKILLS:
if (pCreature->GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS || pCreature->GetCreatureInfo()->trainer_class != CLASS_HUNTER) if (pCreature->GetCreatureInfo()->TrainerType != TRAINER_TYPE_PETS || pCreature->GetCreatureInfo()->TrainerClass != CLASS_HUNTER)
hasMenuItem = false; hasMenuItem = false;
else if (Pet* pet = GetPet()) else if (Pet* pet = GetPet())
{ {
@ -18660,39 +18281,24 @@ void Player::RemovePet(PetSaveMode mode)
pet->Unsummon(mode, this); pet->Unsummon(mode, this);
} }
void Player::BuildPlayerChat(WorldPacket* data, uint8 msgtype, const std::string& text, uint32 language, const char* addonPrefix) const
{
*data << uint8(msgtype);
*data << uint32(language);
*data << GetObjectGuid();
*data << uint32(0); // constant unknown time 4.3.4
if (addonPrefix)
*data << addonPrefix;
else
*data << GetObjectGuid();
*data << uint32(text.length() + 1);
*data << text;
*data << uint8(GetChatTag());
}
void Player::Say(const std::string& text, const uint32 language) void Player::Say(const std::string& text, const uint32 language)
{ {
WorldPacket data(SMSG_MESSAGECHAT, 200); WorldPacket data;
BuildPlayerChat(&data, CHAT_MSG_SAY, text, language); ChatHandler::BuildChatPacket(data, CHAT_MSG_SAY, text.c_str(), Language(language), GetChatTag(), GetObjectGuid(), GetName());
SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY), true); SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY), true);
} }
void Player::Yell(const std::string& text, const uint32 language) void Player::Yell(const std::string& text, const uint32 language)
{ {
WorldPacket data(SMSG_MESSAGECHAT, 200); WorldPacket data;
BuildPlayerChat(&data, CHAT_MSG_YELL, text, language); ChatHandler::BuildChatPacket(data, CHAT_MSG_YELL, text.c_str(), Language(language), GetChatTag(), GetObjectGuid(), GetName());
SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL), true); SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL), true);
} }
void Player::TextEmote(const std::string& text) void Player::TextEmote(const std::string& text)
{ {
WorldPacket data(SMSG_MESSAGECHAT, 200); WorldPacket data;
BuildPlayerChat(&data, CHAT_MSG_EMOTE, text, LANG_UNIVERSAL); ChatHandler::BuildChatPacket(data, CHAT_MSG_EMOTE, text.c_str(), LANG_UNIVERSAL, GetChatTag(), GetObjectGuid(), GetName());
SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), true, !sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHAT)); SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), true, !sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHAT));
} }
@ -18700,12 +18306,12 @@ void Player::Whisper(const std::string& text, uint32 language, ObjectGuid receiv
{ {
Player* rPlayer = sObjectMgr.GetPlayer(receiver); Player* rPlayer = sObjectMgr.GetPlayer(receiver);
WorldPacket data(SMSG_MESSAGECHAT, 200); WorldPacket data;
BuildPlayerChat(&data, CHAT_MSG_WHISPER, text, language); ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, text.c_str(), Language(language), GetChatTag(), GetObjectGuid(), GetName());
rPlayer->GetSession()->SendPacket(&data); rPlayer->GetSession()->SendPacket(&data);
data.Initialize(SMSG_MESSAGECHAT, 200); data.clear();
rPlayer->BuildPlayerChat(&data, CHAT_MSG_WHISPER_INFORM, text, language); ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER_INFORM, text.c_str(), Language(language), CHAT_TAG_NONE, rPlayer->GetObjectGuid());
GetSession()->SendPacket(&data); GetSession()->SendPacket(&data);
if (!isAcceptWhispers()) if (!isAcceptWhispers())
@ -18721,17 +18327,6 @@ void Player::Whisper(const std::string& text, uint32 language, ObjectGuid receiv
ChatHandler(this).PSendSysMessage(LANG_PLAYER_DND, rPlayer->GetName(), rPlayer->autoReplyMsg.c_str()); ChatHandler(this).PSendSysMessage(LANG_PLAYER_DND, rPlayer->GetName(), rPlayer->autoReplyMsg.c_str());
} }
void Player::WhisperAddon(const std::string& text, const std::string& prefix, ObjectGuid receiver)
{
Player* rPlayer = sObjectMgr.GetPlayer(receiver);
std::string _text(text);
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_WHISPER, _text, LANG_UNIVERSAL, prefix.c_str());
rPlayer->GetSession()->SendPacket(&data);
}
void Player::PetSpellInitialize() void Player::PetSpellInitialize()
{ {
Pet* pet = GetPet(); Pet* pet = GetPet();
@ -18745,7 +18340,7 @@ void Player::PetSpellInitialize()
WorldPacket data(SMSG_PET_SPELLS, 8 + 2 + 4 + 4 + 4 * MAX_UNIT_ACTION_BAR_INDEX + 1 + 1); WorldPacket data(SMSG_PET_SPELLS, 8 + 2 + 4 + 4 + 4 * MAX_UNIT_ACTION_BAR_INDEX + 1 + 1);
data << pet->GetObjectGuid(); data << pet->GetObjectGuid();
data << uint16(pet->GetCreatureInfo()->family); // creature family (required for pet talents) data << uint16(pet->GetCreatureInfo()->Family); // creature family (required for pet talents)
data << uint32(0); data << uint32(0);
data << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0); data << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0);
@ -18862,7 +18457,7 @@ void Player::CharmSpellInitialize()
{ {
CreatureInfo const* cinfo = ((Creature*)charm)->GetCreatureInfo(); CreatureInfo const* cinfo = ((Creature*)charm)->GetCreatureInfo();
if (cinfo && cinfo->type == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK) if (cinfo && cinfo->CreatureType == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK)
{ {
for (uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) for (uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
{ {
@ -21486,7 +21081,7 @@ bool Player::isHonorOrXPTarget(Unit* pVictim) const
{ {
if (((Creature*)pVictim)->IsTotem() || if (((Creature*)pVictim)->IsTotem() ||
((Creature*)pVictim)->IsPet() || ((Creature*)pVictim)->IsPet() ||
((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL) ((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_XP_AT_KILL)
return false; return false;
} }
return true; return true;
@ -22808,7 +22403,7 @@ void Player::LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRa
if (!ci) if (!ci)
return; return;
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family); CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->Family);
if (!pet_family) if (!pet_family)
return; return;
@ -23033,7 +22628,7 @@ void Player::BuildPetTalentsInfoData(WorldPacket* data)
if (!ci) if (!ci)
return; return;
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family); CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->Family);
if (!pet_family || pet_family->petTalentType < 0) if (!pet_family || pet_family->petTalentType < 0)
return; return;

View file

@ -43,6 +43,7 @@
#include "ReputationMgr.h" #include "ReputationMgr.h"
#include "BattleGround.h" #include "BattleGround.h"
#include "SharedDefines.h" #include "SharedDefines.h"
#include "Chat.h"
#include<string> #include<string>
#include<vector> #include<vector>
@ -1111,20 +1112,15 @@ class Player : public Unit
void SendInitialPacketsAfterAddToMap(); void SendInitialPacketsAfterAddToMap();
void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time); void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time);
Creature* GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask); Creature* GetNPCIfCanInteractWith(ObjectGuid guid, uint32 NpcFlagsmask);
GameObject* GetGameObjectIfCanInteractWith(ObjectGuid guid, uint32 gameobject_type = MAX_GAMEOBJECT_TYPE) const; GameObject* GetGameObjectIfCanInteractWith(ObjectGuid guid, uint32 gameobject_type = MAX_GAMEOBJECT_TYPE) const;
void ToggleAFK(); void ToggleAFK();
void ToggleDND(); void ToggleDND();
bool isAFK() const bool isAFK() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); }
{ bool isDND() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND); }
return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); ChatTagFlags GetChatTag() const;
}
bool isDND() const
{
return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND);
}
uint8 GetChatTag() const;
std::string autoReplyMsg; std::string autoReplyMsg;
uint32 GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair, uint32 newskintone); uint32 GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair, uint32 newskintone);
@ -1219,8 +1215,6 @@ class Player : public Unit
void Yell(const std::string& text, const uint32 language); void Yell(const std::string& text, const uint32 language);
void TextEmote(const std::string& text); void TextEmote(const std::string& text);
void Whisper(const std::string& text, const uint32 language, ObjectGuid receiver); void Whisper(const std::string& text, const uint32 language, ObjectGuid receiver);
void WhisperAddon(const std::string& text, const std::string& prefix, ObjectGuid receiver);
void BuildPlayerChat(WorldPacket* data, uint8 msgtype, const std::string& text, uint32 language, const char* addonPrefix = NULL) const;
/*********************************************************/ /*********************************************************/
/*** STORAGE SYSTEM ***/ /*** STORAGE SYSTEM ***/

View file

@ -757,10 +757,16 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
case 18153: // Kodo Kombobulator case 18153: // Kodo Kombobulator
case 32312: // Move 1 case 32312: // Move 1
case 37388: // Move 2 case 37388: // Move 2
case 45863: // Cosmetic - Incinerate to Random Target
case 49634: // Sergeant's Flare case 49634: // Sergeant's Flare
case 54530: // Opening case 54530: // Opening
case 56099: // Throw Ice case 56099: // Throw Ice
case 58533: // Return to Stormwind
case 58552: // Return to Orgrimmar
case 62105: // To'kini's Blowgun case 62105: // To'kini's Blowgun
case 63745: // Sara's Blessing
case 63747: // Sara's Fervor
case 64402: // Rocket Strike
return true; return true;
default: default:
break; break;
@ -2220,6 +2226,11 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
if ((spellInfo_1->Id == 62169 && spellInfo_2->Id == 64417) || if ((spellInfo_1->Id == 62169 && spellInfo_2->Id == 64417) ||
(spellInfo_2->Id == 62169 && spellInfo_1->Id == 64417)) (spellInfo_2->Id == 62169 && spellInfo_1->Id == 64417))
return false; return false;
// Auto Grow and Healthy Spore Visual
if ((spellInfo_1->Id == 62559 && spellInfo_2->Id == 62538) ||
(spellInfo_2->Id == 62559 && spellInfo_1->Id == 62538))
return false;
break; break;
} }
case SPELLFAMILY_MAGE: case SPELLFAMILY_MAGE:
@ -3523,9 +3534,9 @@ void SpellMgr::LoadSpellScriptTarget()
} }
if (const CreatureInfo* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(itr->targetEntry)) if (const CreatureInfo* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(itr->targetEntry))
{ {
if (itr->spellId == 30427 && !cInfo->SkinLootId) if (itr->spellId == 30427 && !cInfo->SkinningLootId)
{ {
sLog.outErrorDb("Table `spell_script_target` has creature %u as a target of spellid 30427, but this creature has no skinlootid. Gas extraction will not work!", cInfo->Entry); sLog.outErrorDb("Table `spell_script_target` has creature %u as a target of spellid 30427, but this creature has no skinLootid. Gas extraction will not work!", cInfo->Entry);
sSpellScriptTargetStorage.EraseEntry(itr->spellId); sSpellScriptTargetStorage.EraseEntry(itr->spellId);
continue; continue;
} }
@ -3710,7 +3721,7 @@ bool SpellMgr::LoadPetDefaultSpells_helper(CreatureInfo const* cInfo, PetDefault
return false; return false;
// remove duplicates with levelupSpells if any // remove duplicates with levelupSpells if any
if (PetLevelupSpellSet const* levelupSpells = cInfo->family ? GetPetLevelupSpellList(cInfo->family) : NULL) if (PetLevelupSpellSet const* levelupSpells = cInfo->Family ? GetPetLevelupSpellList(cInfo->Family) : NULL)
{ {
for (int j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j) for (int j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
{ {

View file

@ -883,12 +883,12 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType)
UnitMods unitMod = (attType == BASE_ATTACK ? UNIT_MOD_DAMAGE_MAINHAND : UNIT_MOD_DAMAGE_OFFHAND); UnitMods unitMod = (attType == BASE_ATTACK ? UNIT_MOD_DAMAGE_MAINHAND : UNIT_MOD_DAMAGE_OFFHAND);
/* difference in AP between current attack power and base value from DB */ /* difference in AP between current attack power and base value from DB */
float att_pwr_change = GetTotalAttackPowerValue(attType) - GetCreatureInfo()->attackpower; float att_pwr_change = GetTotalAttackPowerValue(attType) - GetCreatureInfo()->MeleeAttackPower;
float base_value = GetModifierValue(unitMod, BASE_VALUE) + (att_pwr_change * GetAPMultiplier(attType, false) / 14.0f); float base_value = GetModifierValue(unitMod, BASE_VALUE) + (att_pwr_change * GetAPMultiplier(attType, false) / 14.0f);
float base_pct = GetModifierValue(unitMod, BASE_PCT); float base_pct = GetModifierValue(unitMod, BASE_PCT);
float total_value = GetModifierValue(unitMod, TOTAL_VALUE); float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
float total_pct = GetModifierValue(unitMod, TOTAL_PCT); float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
float dmg_multiplier = GetCreatureInfo()->dmg_multiplier; float dmg_multiplier = GetCreatureInfo()->DamageMultiplier;
float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE); float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE); float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);

View file

@ -902,48 +902,11 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
return 0; return 0;
} }
// no xp,health if type 8 /critters/
if (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER)
{
// TODO: fix this part
// Critter may not die of damage taken, instead expect it to run away (no fighting back)
// If (this) is TYPEID_PLAYER, (this) will enter combat w/victim, but after some time, automatically leave combat.
// It is unclear how it should work for other cases.
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamage critter, critter dies");
((Creature*)pVictim)->SetLootRecipient(this);
JustKilledCreature((Creature*)pVictim, NULL);
pVictim->SetHealth(0);
return damage;
}
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamageStart"); DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamageStart");
uint32 health = pVictim->GetHealth(); uint32 health = pVictim->GetHealth();
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "deal dmg:%d to health:%d ", damage, health); DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "deal dmg:%d to health:%d ", damage, health);
// duel ends when player has 1 or less hp
bool duel_hasEnded = false;
if (pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health - 1))
{
// prevent kill only if killed in duel and killed by opponent or opponent controlled creature
if (((Player*)pVictim)->duel->opponent == this || ((Player*)pVictim)->duel->opponent->GetObjectGuid() == GetOwnerGuid())
damage = health - 1;
duel_hasEnded = true;
}
// Get in CombatState
if (pVictim != this && damagetype != DOT)
{
SetInCombatWith(pVictim);
pVictim->SetInCombatWith(this);
if (Player* attackedPlayer = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself())
SetContestedPvP(attackedPlayer);
}
// Rage from Damage made (only from direct weapon damage) // Rage from Damage made (only from direct weapon damage)
if (cleanDamage && damagetype == DIRECT_DAMAGE && this != pVictim && GetTypeId() == TYPEID_PLAYER && (GetPowerType() == POWER_RAGE)) if (cleanDamage && damagetype == DIRECT_DAMAGE && this != pVictim && GetTypeId() == TYPEID_PLAYER && (GetPowerType() == POWER_RAGE))
{ {
@ -978,6 +941,70 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
} }
} }
// no xp,health if type 8 /critters/
if (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER)
{
// TODO: fix this part
// Critter may not die of damage taken, instead expect it to run away (no fighting back)
// If (this) is TYPEID_PLAYER, (this) will enter combat w/victim, but after some time, automatically leave combat.
// It is unclear how it should work for other cases.
DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamage critter, critter dies");
((Creature*)pVictim)->SetLootRecipient(this);
JustKilledCreature((Creature*)pVictim, nullptr);
pVictim->SetHealth(0);
return damage;
}
// share damage by auras
AuraList const& vShareDamageAuras = pVictim->GetAurasByType(SPELL_AURA_SHARE_DAMAGE_PCT);
for (AuraList::const_iterator itr = vShareDamageAuras.begin(); itr != vShareDamageAuras.end(); ++itr)
{
if (!spellProto)
break;
SpellEffectEntry const* spellEffect = spellProto->GetSpellEffect(EFFECT_INDEX_0);
// if damage is done by another shared aura, then skip to avoid circular reference (aura 300 is only applied on effect_idx_0
if (spellEffect && spellEffect->Effect == SPELL_EFFECT_APPLY_AURA &&
spellEffect->EffectApplyAuraName == SPELL_AURA_SHARE_DAMAGE_PCT)
break;
if (Unit* shareTarget = (*itr)->GetCaster())
{
if (shareTarget != pVictim && ((*itr)->GetMiscValue() & damageSchoolMask))
{
SpellEntry const* shareSpell = (*itr)->GetSpellProto();
uint32 shareDamage = uint32(damage*(*itr)->GetModifier()->m_amount / 100.0f);
DealDamageMods(shareTarget, shareDamage, nullptr);
DealDamage(shareTarget, shareDamage, 0, damagetype, GetSpellSchoolMask(shareSpell), shareSpell, false);
}
}
}
// duel ends when player has 1 or less hp
bool duel_hasEnded = false;
if (pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health - 1))
{
// prevent kill only if killed in duel and killed by opponent or opponent controlled creature
if (((Player*)pVictim)->duel->opponent == this || ((Player*)pVictim)->duel->opponent->GetObjectGuid() == GetOwnerGuid())
damage = health - 1;
duel_hasEnded = true;
}
// Get in CombatState
if (pVictim != this && damagetype != DOT)
{
SetInCombatWith(pVictim);
pVictim->SetInCombatWith(this);
if (Player* attackedPlayer = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself())
SetContestedPvP(attackedPlayer);
}
if (GetTypeId() == TYPEID_PLAYER && this != pVictim) if (GetTypeId() == TYPEID_PLAYER && this != pVictim)
{ {
Player* killer = ((Player*)this); Player* killer = ((Player*)this);
@ -1208,11 +1235,6 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
pVictim->AttackedBy(this); pVictim->AttackedBy(this);
} }
if (damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
{
if (!spellProto || !(spellProto->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_DIRECT_DAMAGE))
pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE);
}
if (pVictim->GetTypeId() != TYPEID_PLAYER) if (pVictim->GetTypeId() != TYPEID_PLAYER)
{ {
float threat = damage * sSpellMgr.GetSpellThreatMultiplier(spellProto); float threat = damage * sSpellMgr.GetSpellThreatMultiplier(spellProto);
@ -1245,21 +1267,6 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
} }
} }
// TODO: Store auras by interrupt flag to speed this up.
SpellAuraHolderMap& vAuras = pVictim->GetSpellAuraHolderMap();
for (SpellAuraHolderMap::const_iterator i = vAuras.begin(), next; i != vAuras.end(); i = next)
{
const SpellEntry* se = i->second->GetSpellProto();
next = i; ++next;
if (spellProto && spellProto->Id == se->Id) // Not drop auras added by self
continue;
if (!se->GetProcFlags() && (se->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_DAMAGE))
{
pVictim->RemoveAurasDueToSpell(i->second->GetId());
next = vAuras.begin();
}
}
if (damagetype != NODAMAGE && damage && pVictim->GetTypeId() == TYPEID_PLAYER) if (damagetype != NODAMAGE && damage && pVictim->GetTypeId() == TYPEID_PLAYER)
{ {
if (damagetype != DOT) if (damagetype != DOT)
@ -1426,7 +1433,7 @@ void Unit::JustKilledCreature(Creature* victim, Player* responsiblePlayer)
{ {
if (m->IsRaidOrHeroicDungeon()) if (m->IsRaidOrHeroicDungeon())
{ {
if (victim->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_INSTANCE_BIND) if (victim->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_INSTANCE_BIND)
{ ((DungeonMap*)m)->PermBindAllPlayers(creditedPlayer); } { ((DungeonMap*)m)->PermBindAllPlayers(creditedPlayer); }
} }
else else
@ -1779,7 +1786,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss)
} }
// TODO for melee need create structure as in // TODO for melee need create structure as in
void Unit::CalculateMeleeDamage(Unit* pVictim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType) void Unit::CalculateMeleeDamage(Unit* pVictim, CalcDamageInfo* damageInfo, WeaponAttackType attackType /*= BASE_ATTACK*/)
{ {
damageInfo->attacker = this; damageInfo->attacker = this;
damageInfo->target = pVictim; damageInfo->target = pVictim;
@ -1836,7 +1843,7 @@ void Unit::CalculateMeleeDamage(Unit* pVictim, uint32 damage, CalcDamageInfo* da
damageInfo->cleanDamage = 0; damageInfo->cleanDamage = 0;
return; return;
} }
damage += CalculateDamage(damageInfo->attackType, false); uint32 damage = CalculateDamage(damageInfo->attackType, false);
// Add melee damage bonus // Add melee damage bonus
damage = MeleeDamageBonusDone(damageInfo->target, damage, damageInfo->attackType); damage = MeleeDamageBonusDone(damageInfo->target, damage, damageInfo->attackType);
damage = damageInfo->target->MeleeDamageBonusTaken(this, damage, damageInfo->attackType); damage = damageInfo->target->MeleeDamageBonusTaken(this, damage, damageInfo->attackType);
@ -2909,7 +2916,7 @@ void Unit::AttackerStateUpdate(Unit* pVictim, WeaponAttackType attType, bool ext
pVictim = SelectMagnetTarget(pVictim); pVictim = SelectMagnetTarget(pVictim);
CalcDamageInfo damageInfo; CalcDamageInfo damageInfo;
CalculateMeleeDamage(pVictim, 0, &damageInfo, attType); CalculateMeleeDamage(pVictim, &damageInfo, attType);
// Send log damage message to client // Send log damage message to client
DealDamageMods(pVictim, damageInfo.damage, &damageInfo.absorb); DealDamageMods(pVictim, damageInfo.damage, &damageInfo.absorb);
SendAttackStateUpdate(&damageInfo); SendAttackStateUpdate(&damageInfo);
@ -3028,7 +3035,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* pVictim, WeaponAttackT
else else
parry_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25; parry_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
if (parry_chance > 0 && (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_PARRY))) if (parry_chance > 0 && (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_PARRY)))
{ {
parry_chance -= skillBonus; parry_chance -= skillBonus;
@ -3066,7 +3073,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* pVictim, WeaponAttackT
// check if attack comes from behind, nobody can parry or block if attacker is behind // check if attack comes from behind, nobody can parry or block if attacker is behind
if (!from_behind) if (!from_behind)
{ {
if (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_BLOCK)) if (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_BLOCK))
{ {
tmp = block_chance; tmp = block_chance;
if ((tmp > 0) // check if unit _can_ block if ((tmp > 0) // check if unit _can_ block
@ -3092,7 +3099,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* pVictim, WeaponAttackT
if (GetLevelForTarget(pVictim) >= pVictim->GetLevelForTarget(this) + 4 && if (GetLevelForTarget(pVictim) >= pVictim->GetLevelForTarget(this) + 4 &&
// can be from by creature (if can) or from controlled player that considered as creature // can be from by creature (if can) or from controlled player that considered as creature
((GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->IsPet() && ((GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->IsPet() &&
!(((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_CRUSH)) || !(((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CRUSH)) ||
GetTypeId() == TYPEID_PLAYER && GetCharmerOrOwnerGuid())) GetTypeId() == TYPEID_PLAYER && GetCharmerOrOwnerGuid()))
{ {
// when their weapon skill is 15 or more above victim's defense skill // when their weapon skill is 15 or more above victim's defense skill
@ -3226,7 +3233,7 @@ bool Unit::IsSpellBlocked(Unit* pCaster, SpellEntry const* spellEntry, WeaponAtt
// Check creatures ExtraFlags for disable block // Check creatures ExtraFlags for disable block
if (GetTypeId() == TYPEID_UNIT) if (GetTypeId() == TYPEID_UNIT)
{ {
if (((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_BLOCK) if (((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_BLOCK)
return false; return false;
} }
@ -3363,7 +3370,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* pVictim, SpellEntry const* spell)
if (pVictim->GetTypeId() == TYPEID_UNIT) if (pVictim->GetTypeId() == TYPEID_UNIT)
{ {
uint32 flagEx = ((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags; uint32 flagEx = ((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags;
if (flagEx & CREATURE_FLAG_EXTRA_NO_PARRY) if (flagEx & CREATURE_EXTRA_FLAG_NO_PARRY)
canParry = false; canParry = false;
} }
// Ignore combat result aura // Ignore combat result aura
@ -6225,6 +6232,26 @@ bool Unit::isAttackingPlayer() const
return CheckAllControlledUnits(IsAttackingPlayerHelper(), CONTROLLED_PET | CONTROLLED_TOTEMS | CONTROLLED_GUARDIANS | CONTROLLED_CHARM); return CheckAllControlledUnits(IsAttackingPlayerHelper(), CONTROLLED_PET | CONTROLLED_TOTEMS | CONTROLLED_GUARDIANS | CONTROLLED_CHARM);
} }
bool Unit::CanAttackByItself() const
{
if (!IsVehicle())
return true;
for (uint8 i = 0; i < MAX_VEHICLE_SEAT; ++i)
{
if (uint32 seatId = m_vehicleInfo->GetVehicleEntry()->m_seatID[i])
{
if (VehicleSeatEntry const* seatEntry = sVehicleSeatStore.LookupEntry(seatId))
{
if (seatEntry->m_flags & SEAT_FLAG_CAN_CONTROL)
return false;
}
}
}
return true;
}
void Unit::RemoveAllAttackers() void Unit::RemoveAllAttackers()
{ {
while (!m_attackers.empty()) while (!m_attackers.empty())
@ -8431,7 +8458,7 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy)
{ pCreature->AI()->EnterCombat(enemy); } { pCreature->AI()->EnterCombat(enemy); }
// Some bosses are set into combat with zone // Some bosses are set into combat with zone
if (GetMap()->IsDungeon() && (pCreature->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_AGGRO_ZONE) && enemy && enemy->IsControlledByPlayer()) if (GetMap()->IsDungeon() && (pCreature->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_AGGRO_ZONE) && enemy && enemy->IsControlledByPlayer())
{ pCreature->SetInCombatWithZone(); } { pCreature->SetInCombatWithZone(); }
if (InstanceData* mapInstance = GetInstanceData()) if (InstanceData* mapInstance = GetInstanceData())
@ -8466,7 +8493,7 @@ void Unit::ClearInCombat()
if (GetTypeId() == TYPEID_UNIT) if (GetTypeId() == TYPEID_UNIT)
{ {
Creature* cThis = static_cast<Creature*>(this); Creature* cThis = static_cast<Creature*>(this);
if (cThis->GetCreatureInfo()->unit_flags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !(cThis->GetTemporaryFactionFlags() & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK)) if (cThis->GetCreatureInfo()->UnitFlags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !(cThis->GetTemporaryFactionFlags() & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK))
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE);
clearUnitState(UNIT_STAT_ATTACK_PLAYER); clearUnitState(UNIT_STAT_ATTACK_PLAYER);
@ -8968,10 +8995,10 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced, float ratio, bool ignore
switch (mtype) switch (mtype)
{ {
case MOVE_RUN: case MOVE_RUN:
speed *= ((Creature*)this)->GetCreatureInfo()->speed_run; speed *= ((Creature*)this)->GetCreatureInfo()->SpeedRun;
break; break;
case MOVE_WALK: case MOVE_WALK:
speed *= ((Creature*)this)->GetCreatureInfo()->speed_walk; speed *= ((Creature*)this)->GetCreatureInfo()->SpeedWalk;
break; break;
default: default:
break; break;
@ -9900,7 +9927,7 @@ uint32 Unit::GetCreatureType() const
return CREATURE_TYPE_HUMANOID; return CREATURE_TYPE_HUMANOID;
} }
else else
return ((Creature*)this)->GetCreatureInfo()->type; return ((Creature*)this)->GetCreatureInfo()->CreatureType;
} }
/*####################################### /*#######################################
@ -10816,18 +10843,33 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* pTarget, uint32 procFlag,
if (itr->second->IsDeleted()) if (itr->second->IsDeleted())
continue; continue;
SpellProcEventEntry const* spellProcEvent = NULL; SpellProcEventEntry const* spellProcEvent = nullptr;
// check if that aura is triggered by proc event (then it will be managed by proc handler)
if (!IsTriggeredAtSpellProcEvent(pTarget, itr->second, procSpell, procFlag, procExtra, attType, isVictim, spellProcEvent)) if (!IsTriggeredAtSpellProcEvent(pTarget, itr->second, procSpell, procFlag, procExtra, attType, isVictim, spellProcEvent))
{
// spell seem not managed by proc system, although some case need to be handled
// only process damage case on victim
if (!isVictim || !(procFlag & PROC_FLAG_TAKEN_ANY_DAMAGE))
continue; continue;
const SpellEntry* se = itr->second->GetSpellProto();
// check if the aura is interruptible by damage and if its not just added by this spell (spell who is responsible for this damage is procSpell)
if (se->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_DAMAGE && (!procSpell || procSpell->Id != se->Id))
{
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "ProcDamageAndSpell: Added Spell %u to 'remove aura due to spell' list! Reason: Damage received.", se->Id);
removedSpells.push_back(se->Id);
}
continue;
}
itr->second->SetInUse(true); // prevent holder deletion itr->second->SetInUse(true); // prevent holder deletion
procTriggered.push_back(ProcTriggeredData(spellProcEvent, itr->second)); procTriggered.push_back(ProcTriggeredData(spellProcEvent, itr->second));
} }
// Nothing found if (!procTriggered.empty())
if (procTriggered.empty()) {
return;
// Handle effects proceed this time // Handle effects proceed this time
for (ProcTriggeredList::const_iterator itr = procTriggered.begin(); itr != procTriggered.end(); ++itr) for (ProcTriggeredList::const_iterator itr = procTriggered.begin(); itr != procTriggered.end(); ++itr)
{ {
@ -10908,6 +10950,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* pTarget, uint32 procFlag,
triggeredByHolder->SetInUse(false); triggeredByHolder->SetInUse(false);
} }
}
if (!removedSpells.empty()) if (!removedSpells.empty())
{ {

View file

@ -1253,6 +1253,18 @@ enum IgnoreUnitState
#define REGEN_TIME_PRECISE 500 // Used in Spell::CheckPower for precise regeneration in spell cast time #define REGEN_TIME_PRECISE 500 // Used in Spell::CheckPower for precise regeneration in spell cast time
#define REGEN_TIME_HOLY_POWER 10000 // This determines how often holy power regen is processed #define REGEN_TIME_HOLY_POWER 10000 // This determines how often holy power regen is processed
// Power type values defines
enum PowerDefaults
{
POWER_RAGE_DEFAULT = 1000,
POWER_FOCUS_DEFAULT = 100,
POWER_ENERGY_DEFAULT = 100,
POWER_RUNE_DEFAULT = 8,
POWER_RUNIC_POWER_DEFAULT = 1000,
POWER_HOLY_POWER_DEFAULT = 3,
POWER_SOUL_SHARDS_DEFAULT = 3,
};
struct SpellProcEventEntry; // used only privately struct SpellProcEventEntry; // used only privately
#define MAX_OBJECT_SLOT 5 #define MAX_OBJECT_SLOT 5
@ -1492,6 +1504,11 @@ class Unit : public WorldObject
* @return true if you and/or your pets/minions etc are attacking a player. * @return true if you and/or your pets/minions etc are attacking a player.
*/ */
bool isAttackingPlayer() const; bool isAttackingPlayer() const;
/**
* Checks if wa vehicle is allowed to attack other units by itself.
* @return true if vehicle can attack itself.
*/
bool CanAttackByItself() const;
/** /**
* @return The victim that you are currently attacking * @return The victim that you are currently attacking
*/ */
@ -2120,7 +2137,7 @@ class Unit : public WorldObject
* @param damageInfo this is filled with data about what kind of damage that was done * @param damageInfo this is filled with data about what kind of damage that was done
* @param attackType type of attack, base/off/ranged * @param attackType type of attack, base/off/ranged
*/ */
void CalculateMeleeDamage(Unit* pVictim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK); void CalculateMeleeDamage(Unit* pVictim, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK);
/** /**
* Deals melee damage, if the attack was parried we reduce the victims time until next hit * Deals melee damage, if the attack was parried we reduce the victims time until next hit
* instead of the weapons normal time by 20 or 60%. * instead of the weapons normal time by 20 or 60%.

View file

@ -79,14 +79,24 @@ void OutdoorPvP::HandleGameObjectCreate(GameObject* go)
{ {
// set initial data and activate capture points // set initial data and activate capture points
if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_CAPTURE_POINT) if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_CAPTURE_POINT)
go->SetCapturePointSlider(sOutdoorPvPMgr.GetCapturePointSliderValue(go->GetEntry(), CAPTURE_SLIDER_MIDDLE)); {
CapturePointSliderMap const* capturePoints = sOutdoorPvPMgr.GetCapturePointSliderMap();
CapturePointSliderMap::const_iterator itr = capturePoints->find(go->GetEntry());
if (itr != capturePoints->end())
go->SetCapturePointSlider(itr->second.Value, itr->second.IsLocked);
else
go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE, false);
}
} }
void OutdoorPvP::HandleGameObjectRemove(GameObject* go) void OutdoorPvP::HandleGameObjectRemove(GameObject* go)
{ {
// save capture point slider value (negative value if locked) // save capture point slider value (negative value if locked)
if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_CAPTURE_POINT) if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_CAPTURE_POINT)
sOutdoorPvPMgr.SetCapturePointSlider(go->GetEntry(), go->getLootState() == GO_ACTIVATED ? go->GetCapturePointSlider() : -go->GetCapturePointSlider()); {
CapturePointSlider value(go->GetCapturePointSliderValue(), go->getLootState() != GO_ACTIVATED);
sOutdoorPvPMgr.SetCapturePointSlider(go->GetEntry(), value);
}
} }
/** /**

View file

@ -65,7 +65,7 @@ class OutdoorPvP
virtual bool HandleEvent(uint32 /*eventId*/, GameObject* /*go*/) { return false; } virtual bool HandleEvent(uint32 /*eventId*/, GameObject* /*go*/) { return false; }
// handle capture objective complete // handle capture objective complete
virtual void HandleObjectiveComplete(uint32 /*eventId*/, std::list<Player*> /*players*/, Team /*team*/) {} virtual void HandleObjectiveComplete(uint32 /*eventId*/, const std::list<Player*>& /*players*/, Team /*team*/) {}
// Called when a creature is created // Called when a creature is created
virtual void HandleCreatureCreate(Creature* /*creature*/) {} virtual void HandleCreatureCreate(Creature* /*creature*/) {}

View file

@ -148,7 +148,7 @@ void OutdoorPvPEP::HandleGameObjectCreate(GameObject* go)
} }
} }
void OutdoorPvPEP::HandleObjectiveComplete(uint32 eventId, std::list<Player*> players, Team team) void OutdoorPvPEP::HandleObjectiveComplete(uint32 eventId, const std::list<Player*>& players, Team team)
{ {
uint32 credit = 0; uint32 credit = 0;
@ -174,12 +174,12 @@ void OutdoorPvPEP::HandleObjectiveComplete(uint32 eventId, std::list<Player*> pl
return; return;
} }
for (std::list<Player*>::iterator itr = players.begin(); itr != players.end(); ++itr) for (std::list<Player*>::const_iterator itr = players.begin(); itr != players.end(); ++itr)
{ {
if ((*itr) && (*itr)->GetTeam() == team) if ((*itr) && (*itr)->GetTeam() == team)
{ {
(*itr)->KilledMonsterCredit(credit); (*itr)->KilledMonsterCredit(credit);
(*itr)->RewardHonor(NULL, 1, HONOR_REWARD_PLAGUELANDS); (*itr)->RewardHonor(nullptr, 1, HONOR_REWARD_PLAGUELANDS);
} }
} }
} }

View file

@ -238,7 +238,7 @@ class OutdoorPvPEP : public OutdoorPvP
void SendRemoveWorldStates(Player* player) override; void SendRemoveWorldStates(Player* player) override;
bool HandleEvent(uint32 eventId, GameObject* go) override; bool HandleEvent(uint32 eventId, GameObject* go) override;
void HandleObjectiveComplete(uint32 eventId, std::list<Player*> players, Team team) override; void HandleObjectiveComplete(uint32 eventId, const std::list<Player*>& players, Team team) override;
void HandleCreatureCreate(Creature* creature) override; void HandleCreatureCreate(Creature* creature) override;
void HandleGameObjectCreate(GameObject* go) override; void HandleGameObjectCreate(GameObject* go) override;

View file

@ -143,16 +143,22 @@ void OutdoorPvPGH::LockLighthouse(const WorldObject* objRef)
if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint)) if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint))
go->SetLootState(GO_JUST_DEACTIVATED); go->SetLootState(GO_JUST_DEACTIVATED);
else else
{
// if grid is unloaded, changing the saved slider value is enough // if grid is unloaded, changing the saved slider value is enough
sOutdoorPvPMgr.SetCapturePointSlider(GO_VENTURE_BAY_LIGHTHOUSE, m_zoneOwner == ALLIANCE ? -CAPTURE_SLIDER_ALLIANCE : -CAPTURE_SLIDER_HORDE); CapturePointSlider value(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE, true);
sOutdoorPvPMgr.SetCapturePointSlider(GO_VENTURE_BAY_LIGHTHOUSE, value);
}
} }
// Handle Lighthouse unlock when the commander is killed // Handle Lighthouse unlock when the commander is killed
void OutdoorPvPGH::UnlockLighthouse(const WorldObject* objRef) void OutdoorPvPGH::UnlockLighthouse(const WorldObject* objRef)
{ {
if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint)) if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint))
go->SetCapturePointSlider(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE); go->SetLootState(GO_ACTIVATED);
else else
// if grid is unloaded, resetting the saved slider value is enough {
sOutdoorPvPMgr.SetCapturePointSlider(GO_VENTURE_BAY_LIGHTHOUSE, m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE); // if grid is unloaded, changing the saved slider value is enough
CapturePointSlider value(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE, false);
sOutdoorPvPMgr.SetCapturePointSlider(GO_VENTURE_BAY_LIGHTHOUSE, value);
}
} }

View file

@ -114,7 +114,7 @@ void OutdoorPvPHP::HandleGameObjectCreate(GameObject* go)
} }
} }
void OutdoorPvPHP::HandleObjectiveComplete(uint32 eventId, std::list<Player*> players, Team team) void OutdoorPvPHP::HandleObjectiveComplete(uint32 eventId, const std::list<Player*>& players, Team team)
{ {
uint32 credit = 0; uint32 credit = 0;
@ -136,12 +136,12 @@ void OutdoorPvPHP::HandleObjectiveComplete(uint32 eventId, std::list<Player*> pl
return; return;
} }
for (std::list<Player*>::iterator itr = players.begin(); itr != players.end(); ++itr) for (std::list<Player*>::const_iterator itr = players.begin(); itr != players.end(); ++itr)
{ {
if ((*itr) && (*itr)->GetTeam() == team) if ((*itr) && (*itr)->GetTeam() == team)
{ {
(*itr)->KilledMonsterCredit(credit); (*itr)->KilledMonsterCredit(credit);
(*itr)->RewardHonor(NULL, 1, HONOR_REWARD_HELLFIRE); (*itr)->RewardHonor(nullptr, 1, HONOR_REWARD_HELLFIRE);
} }
} }
} }

View file

@ -159,7 +159,7 @@ class OutdoorPvPHP : public OutdoorPvP
void SendRemoveWorldStates(Player* player) override; void SendRemoveWorldStates(Player* player) override;
bool HandleEvent(uint32 eventId, GameObject* go) override; bool HandleEvent(uint32 eventId, GameObject* go) override;
void HandleObjectiveComplete(uint32 eventId, std::list<Player*> players, Team team) override; void HandleObjectiveComplete(uint32 eventId, const std::list<Player*>& players, Team team) override;
void HandleGameObjectCreate(GameObject* go) override; void HandleGameObjectCreate(GameObject* go) override;
void HandlePlayerKillInsideArea(Player* player) override; void HandlePlayerKillInsideArea(Player* player) override;

View file

@ -167,19 +167,3 @@ void OutdoorPvPMgr::Update(uint32 diff)
m_updateTimer.Reset(); m_updateTimer.Reset();
} }
/**
Function that gets the capture point slider value
@param capture point entry
@param default value being returned if no saved value for the capture point was found
*/
float OutdoorPvPMgr::GetCapturePointSliderValue(uint32 entry, float defaultValue)
{
CapturePointSliderMap::const_iterator itr = m_capturePointSlider.find(entry);
if (itr != m_capturePointSlider.end())
return itr->second;
// return default value if we can't find any
return defaultValue;
}

View file

@ -79,11 +79,22 @@ enum OutdoorPvPZones
ZONE_ID_GRIZZLY_HILLS = 394 ZONE_ID_GRIZZLY_HILLS = 394
}; };
struct CapturePointSlider
{
CapturePointSlider() : Value(0.0f), IsLocked(false) {}
CapturePointSlider(float value, bool isLocked) : Value(value), IsLocked(isLocked) {}
float Value;
bool IsLocked;
};
class Player; class Player;
class GameObject; class GameObject;
class Creature; class Creature;
class OutdoorPvP; class OutdoorPvP;
typedef std::map<uint32 /*capture point entry*/, CapturePointSlider /*slider value and lock state*/> CapturePointSliderMap;
class OutdoorPvPMgr class OutdoorPvPMgr
{ {
public: public:
@ -104,9 +115,9 @@ class OutdoorPvPMgr
void Update(uint32 diff); void Update(uint32 diff);
// Save and load capture point slider values // Save and load capture point slider
float GetCapturePointSliderValue(uint32 entry, float defaultValue); CapturePointSliderMap const* GetCapturePointSliderMap() const { return &m_capturePointSlider; }
void SetCapturePointSlider(uint32 entry, float value) { m_capturePointSlider[entry] = value; } void SetCapturePointSlider(uint32 entry, CapturePointSlider value) { m_capturePointSlider[entry] = value; }
private: private:
// return assigned outdoor pvp script // return assigned outdoor pvp script
@ -115,8 +126,6 @@ class OutdoorPvPMgr
// contains all outdoor pvp scripts // contains all outdoor pvp scripts
OutdoorPvP* m_scripts[MAX_OPVP_ID]; OutdoorPvP* m_scripts[MAX_OPVP_ID];
typedef std::map<uint32 /*capture point entry*/, float /*slider value*/> CapturePointSliderMap;
CapturePointSliderMap m_capturePointSlider; CapturePointSliderMap m_capturePointSlider;
// update interval // update interval

View file

@ -85,11 +85,11 @@ void OutdoorPvPNA::HandlePlayerLeaveZone(Player* player, bool isMainZone)
OutdoorPvP::HandlePlayerLeaveZone(player, isMainZone); OutdoorPvP::HandlePlayerLeaveZone(player, isMainZone);
} }
void OutdoorPvPNA::HandleObjectiveComplete(uint32 eventId, std::list<Player*> players, Team team) void OutdoorPvPNA::HandleObjectiveComplete(uint32 eventId, const std::list<Player*>& players, Team team)
{ {
if (eventId == EVENT_HALAA_BANNER_WIN_ALLIANCE || eventId == EVENT_HALAA_BANNER_WIN_HORDE) if (eventId == EVENT_HALAA_BANNER_WIN_ALLIANCE || eventId == EVENT_HALAA_BANNER_WIN_HORDE)
{ {
for (std::list<Player*>::iterator itr = players.begin(); itr != players.end(); ++itr) for (std::list<Player*>::const_iterator itr = players.begin(); itr != players.end(); ++itr)
{ {
if ((*itr) && (*itr)->GetTeam() == team) if ((*itr) && (*itr)->GetTeam() == team)
(*itr)->KilledMonsterCredit(NPC_HALAA_COMBATANT); (*itr)->KilledMonsterCredit(NPC_HALAA_COMBATANT);
@ -550,16 +550,22 @@ void OutdoorPvPNA::LockHalaa(const WorldObject* objRef)
if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint)) if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint))
go->SetLootState(GO_JUST_DEACTIVATED); go->SetLootState(GO_JUST_DEACTIVATED);
else else
{
// if grid is unloaded, changing the saved slider value is enough // if grid is unloaded, changing the saved slider value is enough
sOutdoorPvPMgr.SetCapturePointSlider(GO_HALAA_BANNER, m_zoneOwner == ALLIANCE ? -CAPTURE_SLIDER_ALLIANCE : -CAPTURE_SLIDER_HORDE); CapturePointSlider value(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE, true);
sOutdoorPvPMgr.SetCapturePointSlider(GO_HALAA_BANNER, value);
}
} }
// Unlock Halaa when all the soldiers are killed // Unlock Halaa when all the soldiers are killed
void OutdoorPvPNA::UnlockHalaa(const WorldObject* objRef) void OutdoorPvPNA::UnlockHalaa(const WorldObject* objRef)
{ {
if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint)) if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint))
go->SetCapturePointSlider(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE); go->SetLootState(GO_ACTIVATED);
else else
// if grid is unloaded, resetting the saved slider value is enough {
sOutdoorPvPMgr.SetCapturePointSlider(GO_HALAA_BANNER, m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE); // if grid is unloaded, changing the saved slider value is enough
CapturePointSlider value(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE, false);
sOutdoorPvPMgr.SetCapturePointSlider(GO_HALAA_BANNER, value);
}
} }

View file

@ -168,7 +168,7 @@ class OutdoorPvPNA : public OutdoorPvP
void SendRemoveWorldStates(Player* player) override; void SendRemoveWorldStates(Player* player) override;
bool HandleEvent(uint32 eventId, GameObject* go) override; bool HandleEvent(uint32 eventId, GameObject* go) override;
void HandleObjectiveComplete(uint32 eventId, std::list<Player*> players, Team team) override; void HandleObjectiveComplete(uint32 eventId, const std::list<Player*>& players, Team team) override;
void HandleCreatureCreate(Creature* creature) override; void HandleCreatureCreate(Creature* creature) override;
void HandleGameObjectCreate(GameObject* go) override; void HandleGameObjectCreate(GameObject* go) override;

View file

@ -118,7 +118,7 @@ void OutdoorPvPTF::HandleGameObjectCreate(GameObject* go)
} }
} }
void OutdoorPvPTF::HandleObjectiveComplete(uint32 eventId, std::list<Player*> players, Team team) void OutdoorPvPTF::HandleObjectiveComplete(uint32 eventId, const std::list<Player*>& players, Team team)
{ {
for (uint8 i = 0; i < MAX_TF_TOWERS; ++i) for (uint8 i = 0; i < MAX_TF_TOWERS; ++i)
{ {
@ -126,7 +126,7 @@ void OutdoorPvPTF::HandleObjectiveComplete(uint32 eventId, std::list<Player*> pl
{ {
if (terokkarTowerEvents[i][j].eventEntry == eventId) if (terokkarTowerEvents[i][j].eventEntry == eventId)
{ {
for (std::list<Player*>::iterator itr = players.begin(); itr != players.end(); ++itr) for (std::list<Player*>::const_iterator itr = players.begin(); itr != players.end(); ++itr)
{ {
if ((*itr) && (*itr)->GetTeam() == team) if ((*itr) && (*itr)->GetTeam() == team)
(*itr)->AreaExploredOrEventHappens(team == ALLIANCE ? QUEST_SPIRITS_OF_AUCHINDOUM_ALLIANCE : QUEST_SPIRITS_OF_AUCHINDOUM_HORDE); (*itr)->AreaExploredOrEventHappens(team == ALLIANCE ? QUEST_SPIRITS_OF_AUCHINDOUM_ALLIANCE : QUEST_SPIRITS_OF_AUCHINDOUM_HORDE);
@ -351,8 +351,11 @@ void OutdoorPvPTF::LockTowers(const WorldObject* objRef)
if (GameObject* go = objRef->GetMap()->GetGameObject(m_towerBanners[i])) if (GameObject* go = objRef->GetMap()->GetGameObject(m_towerBanners[i]))
go->SetLootState(GO_JUST_DEACTIVATED); go->SetLootState(GO_JUST_DEACTIVATED);
else else
{
// if grid is unloaded, changing the saved slider value is enough // if grid is unloaded, changing the saved slider value is enough
sOutdoorPvPMgr.SetCapturePointSlider(terokkarTowers[i], m_zoneOwner == ALLIANCE ? -CAPTURE_SLIDER_ALLIANCE : -CAPTURE_SLIDER_HORDE); CapturePointSlider value(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE, true);
sOutdoorPvPMgr.SetCapturePointSlider(terokkarTowers[i], value);
}
} }
} }
@ -363,12 +366,15 @@ void OutdoorPvPTF::ResetTowers(const WorldObject* objRef)
{ {
if (GameObject* go = objRef->GetMap()->GetGameObject(m_towerBanners[i])) if (GameObject* go = objRef->GetMap()->GetGameObject(m_towerBanners[i]))
{ {
go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE); go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE, false);
// visual update needed because banner still has artkit from previous owner // visual update needed because banner still has artkit from previous owner
SetBannerVisual(go, CAPTURE_ARTKIT_NEUTRAL, CAPTURE_ANIM_NEUTRAL); SetBannerVisual(go, CAPTURE_ARTKIT_NEUTRAL, CAPTURE_ANIM_NEUTRAL);
} }
else else
// if grid is unloaded, resetting the saved slider value is enough {
sOutdoorPvPMgr.SetCapturePointSlider(terokkarTowers[i], CAPTURE_SLIDER_MIDDLE); // if grid is unloaded, changing the saved slider value is enough
CapturePointSlider value(CAPTURE_SLIDER_MIDDLE, false);
sOutdoorPvPMgr.SetCapturePointSlider(terokkarTowers[i], value);
}
} }
} }

View file

@ -169,7 +169,7 @@ class OutdoorPvPTF : public OutdoorPvP
void SendRemoveWorldStates(Player* player) override; void SendRemoveWorldStates(Player* player) override;
bool HandleEvent(uint32 eventId, GameObject* go) override; bool HandleEvent(uint32 eventId, GameObject* go) override;
void HandleObjectiveComplete(uint32 eventId, std::list<Player*> players, Team team) override; void HandleObjectiveComplete(uint32 eventId, const std::list<Player*>& players, Team team) override;
void HandleGameObjectCreate(GameObject* go) override; void HandleGameObjectCreate(GameObject* go) override;
void Update(uint32 diff) override; void Update(uint32 diff) override;

View file

@ -3779,7 +3779,7 @@ enum MaxLevel
static const MaxLevel maxLevelForExpansion[MAX_EXPANSION + 1] = { MAX_LEVEL_CLASSIC, MAX_LEVEL_TBC, MAX_LEVEL_WOTLK, MAX_LEVEL_CATACLYSM }; static const MaxLevel maxLevelForExpansion[MAX_EXPANSION + 1] = { MAX_LEVEL_CLASSIC, MAX_LEVEL_TBC, MAX_LEVEL_WOTLK, MAX_LEVEL_CATACLYSM };
// Max creature level (included some bosses and elite) // Max creature level (included some bosses and elite)
#define DEFAULT_MAX_CREATURE_LEVEL 85 #define DEFAULT_MAX_CREATURE_LEVEL 90
// This spell is used for general boarding serverside // This spell is used for general boarding serverside
#define SPELL_RIDE_VEHICLE_HARDCODED 46598 #define SPELL_RIDE_VEHICLE_HARDCODED 46598

View file

@ -1042,7 +1042,7 @@ enum MangosStrings
// Use for custom patches 11000-11999 // Use for custom patches 11000-11999
// NOT RESERVED IDS 12000-1999999999 // NOT RESERVED IDS 12000-1999999999
// `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID) // `db_script_string` table index 2000000000-2000999999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID)
// For other tables maybe 2000010000-2147483647 (max index) // For other tables maybe 2001000000-2147483647 (max index)
}; };
#endif #endif

View file

@ -246,12 +246,13 @@ bool AccountMgr::CheckPassword(uint32 accid, std::string passwd)
bool AccountMgr::normalizeString(std::string& utf8str) bool AccountMgr::normalizeString(std::string& utf8str)
{ {
wchar_t wstr_buf[MAX_ACCOUNT_STR + 1]; wchar_t wstr_buf[MAX_ACCOUNT_STR + 1];
size_t wstr_len = MAX_ACCOUNT_STR; size_t wstr_len = MAX_ACCOUNT_STR;
if (!Utf8toWStr(utf8str, wstr_buf, wstr_len)) if (!Utf8toWStr(utf8str, wstr_buf, wstr_len))
return false; return false;
std::transform(&wstr_buf[0], wstr_buf + wstr_len, &wstr_buf[0], wcharToUpperOnlyLatin); for (uint32 i = 0; i <= wstr_len; ++i)
wstr_buf[i] = wcharToUpperOnlyLatin(wstr_buf[i]);
return WStrToUtf8(wstr_buf, wstr_len, utf8str); return WStrToUtf8(wstr_buf, wstr_len, utf8str);
} }

View file

@ -47,6 +47,7 @@
#include "Map.h" #include "Map.h"
#include "InstanceData.h" #include "InstanceData.h"
#include "DBCStructure.h" #include "DBCStructure.h"
#include "Chat.h"
#include "Policies/Singleton.h" #include "Policies/Singleton.h"
@ -63,15 +64,8 @@ namespace MaNGOS
{ {
char const* text = sObjectMgr.GetMangosString(i_textId, loc_idx); char const* text = sObjectMgr.GetMangosString(i_textId, loc_idx);
data << uint8(i_msgtype); ChatHandler::BuildChatPacket(data, i_msgtype, text, LANG_UNIVERSAL, i_player.GetChatTag(), i_player.GetObjectGuid(), nullptr, i_player.GetObjectGuid(), nullptr, nullptr,
data << uint32(LANG_UNIVERSAL); i_achievementId);
data << i_player.GetObjectGuid();
data << uint32(5);
data << i_player.GetObjectGuid();
data << uint32(strlen(text) + 1);
data << text;
data << uint8(0);
data << uint32(i_achievementId);
} }
private: private:

File diff suppressed because it is too large Load diff

View file

@ -166,26 +166,26 @@ class Channel
uint8 GetFlags() const { return m_flags; } uint8 GetFlags() const { return m_flags; }
bool HasFlag(uint8 flag) { return m_flags & flag; } bool HasFlag(uint8 flag) { return m_flags & flag; }
void Join(ObjectGuid p, const char* pass); void Join(Player* player, const char* password);
void Leave(ObjectGuid p, bool send = true); void Leave(Player* player, bool send = true);
void KickOrBan(ObjectGuid good, const char* badname, bool ban); void KickOrBan(Player* player, const char* targetName, bool ban);
void Kick(ObjectGuid good, const char* badname) { KickOrBan(good, badname, false); } void Kick(Player* player, const char* targetName) { KickOrBan(player, targetName, false); }
void Ban(ObjectGuid good, const char* badname) { KickOrBan(good, badname, true); } void Ban(Player* player, const char* targetName) { KickOrBan(player, targetName, true); }
void UnBan(ObjectGuid good, const char* badname); void UnBan(Player* player, const char* targetName);
void Password(ObjectGuid p, const char* pass); void Password(Player* player, const char* password);
void SetMode(ObjectGuid p, const char* p2n, bool mod, bool set); void SetMode(Player* player, const char* targetName, bool moderator, bool set);
void SetOwner(ObjectGuid p, bool exclaim = true); void SetOwner(ObjectGuid guid, bool exclaim = true);
void SetOwner(ObjectGuid p, const char* newname); void SetOwner(Player* player, const char* targetName);
void SendWhoOwner(ObjectGuid p); void SendWhoOwner(Player* player);
void SetModerator(ObjectGuid p, const char* newname) { SetMode(p, newname, true, true); } void SetModerator(Player* player, const char* targetName) { SetMode(player, targetName, true, true); }
void UnsetModerator(ObjectGuid p, const char* newname) { SetMode(p, newname, true, false); } void UnsetModerator(Player* player, const char* targetName) { SetMode(player, targetName, true, false); }
void SetMute(ObjectGuid p, const char* newname) { SetMode(p, newname, false, true); } void SetMute(Player* player, const char* targetName) { SetMode(player, targetName, false, true); }
void UnsetMute(ObjectGuid p, const char* newname) { SetMode(p, newname, false, false); } void UnsetMute(Player* player, const char* targetName) { SetMode(player, targetName, false, false); }
void List(Player* p); void List(Player* player);
void Announce(ObjectGuid p); void Announce(Player* player);
void Moderate(ObjectGuid p); void Moderate(Player* player);
void Say(ObjectGuid p, const char* what, uint32 lang); void Say(Player* player, const char* text, uint32 lang);
void Invite(ObjectGuid p, const char* newp); void Invite(Player* player, const char* targetName);
void Voice(ObjectGuid guid1, ObjectGuid guid2); void Voice(ObjectGuid guid1, ObjectGuid guid2);
void DeVoice(ObjectGuid guid1, ObjectGuid guid2); void DeVoice(ObjectGuid guid1, ObjectGuid guid2);
void JoinNotify(ObjectGuid guid); // invisible notify void JoinNotify(ObjectGuid guid); // invisible notify
@ -213,11 +213,11 @@ class Channel
void MakeModerationOn(WorldPacket* data, ObjectGuid guid); //+ 0x0F void MakeModerationOn(WorldPacket* data, ObjectGuid guid); //+ 0x0F
void MakeModerationOff(WorldPacket* data, ObjectGuid guid); //+ 0x10 void MakeModerationOff(WorldPacket* data, ObjectGuid guid); //+ 0x10
void MakeMuted(WorldPacket* data); //? 0x11 void MakeMuted(WorldPacket* data); //? 0x11
void MakePlayerKicked(WorldPacket* data, ObjectGuid bad, ObjectGuid good);//? 0x12 void MakePlayerKicked(WorldPacket* data, ObjectGuid target, ObjectGuid source);//? 0x12
void MakeBanned(WorldPacket* data); //? 0x13 void MakeBanned(WorldPacket* data); //? 0x13
void MakePlayerBanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good);//? 0x14 void MakePlayerBanned(WorldPacket* data, ObjectGuid target, ObjectGuid source);//? 0x14
void MakePlayerUnbanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good);//? 0x15 void MakePlayerUnbanned(WorldPacket* data, ObjectGuid target, ObjectGuid source);//? 0x15
void MakePlayerNotBanned(WorldPacket* data, ObjectGuid guid); //? 0x16 void MakePlayerNotBanned(WorldPacket* data, const std::string& name); //? 0x16
void MakePlayerAlreadyMember(WorldPacket* data, ObjectGuid guid); //+ 0x17 void MakePlayerAlreadyMember(WorldPacket* data, ObjectGuid guid); //+ 0x17
void MakeInvite(WorldPacket* data, ObjectGuid guid); //? 0x18 void MakeInvite(WorldPacket* data, ObjectGuid guid); //? 0x18
void MakeInviteWrongFaction(WorldPacket* data); //? 0x19 void MakeInviteWrongFaction(WorldPacket* data); //? 0x19
@ -225,50 +225,50 @@ class Channel
void MakeInvalidName(WorldPacket* data); //? 0x1B void MakeInvalidName(WorldPacket* data); //? 0x1B
void MakeNotModerated(WorldPacket* data); //? 0x1C void MakeNotModerated(WorldPacket* data); //? 0x1C
void MakePlayerInvited(WorldPacket* data, const std::string& name); //+ 0x1D void MakePlayerInvited(WorldPacket* data, const std::string& name); //+ 0x1D
void MakePlayerInviteBanned(WorldPacket* data, ObjectGuid guid); //? 0x1E void MakePlayerInviteBanned(WorldPacket* data, const std::string& name);//? 0x1E
void MakeThrottled(WorldPacket* data); //? 0x1F void MakeThrottled(WorldPacket* data); //? 0x1F
void MakeNotInArea(WorldPacket* data); //? 0x20 void MakeNotInArea(WorldPacket* data); //? 0x20
void MakeNotInLfg(WorldPacket* data); //? 0x21 void MakeNotInLfg(WorldPacket* data); //? 0x21
void MakeVoiceOn(WorldPacket* data, ObjectGuid guid); //+ 0x22 void MakeVoiceOn(WorldPacket* data, ObjectGuid guid); //+ 0x22
void MakeVoiceOff(WorldPacket* data, ObjectGuid guid); //+ 0x23 void MakeVoiceOff(WorldPacket* data, ObjectGuid guid); //+ 0x23
void SendToAll(WorldPacket* data, ObjectGuid p = ObjectGuid()); void SendToAll(WorldPacket* data, ObjectGuid guid = ObjectGuid());
void SendToOne(WorldPacket* data, ObjectGuid who); void SendToOne(WorldPacket* data, ObjectGuid who);
bool IsOn(ObjectGuid who) const { return m_players.find(who) != m_players.end(); } bool IsOn(ObjectGuid who) const { return m_players.find(who) != m_players.end(); }
bool IsBanned(ObjectGuid guid) const { return m_banned.find(guid) != m_banned.end(); } bool IsBanned(ObjectGuid guid) const { return m_banned.find(guid) != m_banned.end(); }
uint8 GetPlayerFlags(ObjectGuid p) const uint8 GetPlayerFlags(ObjectGuid guid) const
{ {
PlayerList::const_iterator p_itr = m_players.find(p); PlayerList::const_iterator p_itr = m_players.find(guid);
if (p_itr == m_players.end()) if (p_itr == m_players.end())
return 0; return 0;
return p_itr->second.flags; return p_itr->second.flags;
} }
void SetModerator(ObjectGuid p, bool set) void SetModerator(ObjectGuid guid, bool set)
{ {
if (m_players[p].IsModerator() != set) if (m_players[guid].IsModerator() != set)
{ {
uint8 oldFlag = GetPlayerFlags(p); uint8 oldFlag = GetPlayerFlags(guid);
m_players[p].SetModerator(set); m_players[guid].SetModerator(set);
WorldPacket data; WorldPacket data;
MakeModeChange(&data, p, oldFlag); MakeModeChange(&data, guid, oldFlag);
SendToAll(&data); SendToAll(&data);
} }
} }
void SetMute(ObjectGuid p, bool set) void SetMute(ObjectGuid guid, bool set)
{ {
if (m_players[p].IsMuted() != set) if (m_players[guid].IsMuted() != set)
{ {
uint8 oldFlag = GetPlayerFlags(p); uint8 oldFlag = GetPlayerFlags(guid);
m_players[p].SetMuted(set); m_players[guid].SetMuted(set);
WorldPacket data; WorldPacket data;
MakeModeChange(&data, p, oldFlag); MakeModeChange(&data, guid, oldFlag);
SendToAll(&data); SendToAll(&data);
} }
} }

View file

@ -45,14 +45,15 @@ void WorldSession::HandleJoinChannelOpcode(WorldPacket& recvPacket)
return; return;
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetJoinChannel(channelname, channel_id)) // channel id seems to be useless but must be checked for LFG if (Channel* chn = cMgr->GetJoinChannel(channelname, channel_id))
chn->Join(_player->GetObjectGuid(), pass.c_str()); chn->Join(_player, pass.c_str());
} }
void WorldSession::HandleLeaveChannelOpcode(WorldPacket& recvPacket) void WorldSession::HandleLeaveChannelOpcode(WorldPacket& recvPacket)
{ {
DEBUG_LOG("WORLD: Received opcode %s (%u, 0x%X)", recvPacket.GetOpcodeName(), recvPacket.GetOpcode(), recvPacket.GetOpcode()); DEBUG_LOG("WORLD: Received opcode %s (%u, 0x%X)", recvPacket.GetOpcodeName(), recvPacket.GetOpcode(), recvPacket.GetOpcode());
// recvPacket.hexlike(); // recvPacket.hexlike();
uint32 unk; uint32 unk;
std::string channelname; std::string channelname;
recvPacket >> unk; // channel id? recvPacket >> unk; // channel id?
@ -64,7 +65,7 @@ void WorldSession::HandleLeaveChannelOpcode(WorldPacket& recvPacket)
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
{ {
if (Channel* chn = cMgr->GetChannel(channelname, _player)) if (Channel* chn = cMgr->GetChannel(channelname, _player))
chn->Leave(_player->GetObjectGuid(), true); chn->Leave(_player, true);
cMgr->LeftChannel(channelname); cMgr->LeftChannel(channelname);
} }
} }
@ -94,7 +95,7 @@ void WorldSession::HandleChannelPasswordOpcode(WorldPacket& recvPacket)
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetChannel(channelname, _player)) if (Channel* chn = cMgr->GetChannel(channelname, _player))
chn->Password(_player->GetObjectGuid(), pass.c_str()); chn->Password(_player, pass.c_str());
} }
void WorldSession::HandleChannelSetOwnerOpcode(WorldPacket& recvPacket) void WorldSession::HandleChannelSetOwnerOpcode(WorldPacket& recvPacket)
@ -126,7 +127,7 @@ void WorldSession::HandleChannelOwnerOpcode(WorldPacket& recvPacket)
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetChannel(channelname, _player)) if (Channel* chn = cMgr->GetChannel(channelname, _player))
chn->SendWhoOwner(_player->GetObjectGuid()); chn->SendWhoOwner(_player);
} }
void WorldSession::HandleChannelModeratorOpcode(WorldPacket& recvPacket) void WorldSession::HandleChannelModeratorOpcode(WorldPacket& recvPacket)
@ -146,7 +147,7 @@ void WorldSession::HandleChannelModeratorOpcode(WorldPacket& recvPacket)
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetChannel(channelname, _player)) if (Channel* chn = cMgr->GetChannel(channelname, _player))
chn->SetModerator(_player->GetObjectGuid(), otp.c_str()); chn->SetModerator(_player, otp.c_str());
} }
void WorldSession::HandleChannelUnmoderatorOpcode(WorldPacket& recvPacket) void WorldSession::HandleChannelUnmoderatorOpcode(WorldPacket& recvPacket)
@ -156,17 +157,17 @@ void WorldSession::HandleChannelUnmoderatorOpcode(WorldPacket& recvPacket)
uint32 channelLen, nameLen; uint32 channelLen, nameLen;
std::string channelname, otp; std::string channelname, otp;
nameLen = recvPacket.ReadBits(7);
channelLen = recvPacket.ReadBits(8); channelLen = recvPacket.ReadBits(8);
channelname = recvPacket.ReadString(channelLen); nameLen = recvPacket.ReadBits(7);
otp = recvPacket.ReadString(nameLen); otp = recvPacket.ReadString(nameLen);
channelname = recvPacket.ReadString(channelLen);
if (!normalizePlayerName(otp)) if (!normalizePlayerName(otp))
return; return;
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetChannel(channelname, _player)) if (Channel* chn = cMgr->GetChannel(channelname, _player))
chn->UnsetModerator(_player->GetObjectGuid(), otp.c_str()); chn->UnsetMute(_player, otp.c_str());
} }
void WorldSession::HandleChannelMuteOpcode(WorldPacket& recvPacket) void WorldSession::HandleChannelMuteOpcode(WorldPacket& recvPacket)
@ -176,17 +177,17 @@ void WorldSession::HandleChannelMuteOpcode(WorldPacket& recvPacket)
uint32 channelLen, nameLen; uint32 channelLen, nameLen;
std::string channelname, otp; std::string channelname, otp;
channelLen = recvPacket.ReadBits(8);
nameLen = recvPacket.ReadBits(7); nameLen = recvPacket.ReadBits(7);
channelname = recvPacket.ReadString(channelLen); channelLen = recvPacket.ReadBits(8);
otp = recvPacket.ReadString(nameLen); otp = recvPacket.ReadString(nameLen);
channelname = recvPacket.ReadString(channelLen);
if (!normalizePlayerName(otp)) if (!normalizePlayerName(otp))
return; return;
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetChannel(channelname, _player)) if (Channel* chn = cMgr->GetChannel(channelname, _player))
chn->SetMute(_player->GetObjectGuid(), otp.c_str()); chn->Invite(_player, otp.c_str());
} }
void WorldSession::HandleChannelUnmuteOpcode(WorldPacket& recvPacket) void WorldSession::HandleChannelUnmuteOpcode(WorldPacket& recvPacket)
@ -206,7 +207,7 @@ void WorldSession::HandleChannelUnmuteOpcode(WorldPacket& recvPacket)
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetChannel(channelname, _player)) if (Channel* chn = cMgr->GetChannel(channelname, _player))
chn->UnsetMute(_player->GetObjectGuid(), otp.c_str()); chn->UnsetMute(_player, otp.c_str());
} }
void WorldSession::HandleChannelInviteOpcode(WorldPacket& recvPacket) void WorldSession::HandleChannelInviteOpcode(WorldPacket& recvPacket)
@ -226,7 +227,7 @@ void WorldSession::HandleChannelInviteOpcode(WorldPacket& recvPacket)
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetChannel(channelname, _player)) if (Channel* chn = cMgr->GetChannel(channelname, _player))
chn->Invite(_player->GetObjectGuid(), otp.c_str()); chn->Invite(_player, otp.c_str());
} }
void WorldSession::HandleChannelKickOpcode(WorldPacket& recvPacket) void WorldSession::HandleChannelKickOpcode(WorldPacket& recvPacket)
@ -246,7 +247,7 @@ void WorldSession::HandleChannelKickOpcode(WorldPacket& recvPacket)
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetChannel(channelname, _player)) if (Channel* chn = cMgr->GetChannel(channelname, _player))
chn->Kick(_player->GetObjectGuid(), otp.c_str()); chn->Kick(_player, otp.c_str());
} }
void WorldSession::HandleChannelBanOpcode(WorldPacket& recvPacket) void WorldSession::HandleChannelBanOpcode(WorldPacket& recvPacket)
@ -266,7 +267,7 @@ void WorldSession::HandleChannelBanOpcode(WorldPacket& recvPacket)
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetChannel(channelname, _player)) if (Channel* chn = cMgr->GetChannel(channelname, _player))
chn->Ban(_player->GetObjectGuid(), otp.c_str()); chn->Ban(_player, otp.c_str());
} }
void WorldSession::HandleChannelUnbanOpcode(WorldPacket& recvPacket) void WorldSession::HandleChannelUnbanOpcode(WorldPacket& recvPacket)
@ -286,7 +287,7 @@ void WorldSession::HandleChannelUnbanOpcode(WorldPacket& recvPacket)
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetChannel(channelname, _player)) if (Channel* chn = cMgr->GetChannel(channelname, _player))
chn->UnBan(_player->GetObjectGuid(), otp.c_str()); chn->UnBan(_player, otp.c_str());
} }
void WorldSession::HandleChannelAnnouncementsOpcode(WorldPacket& recvPacket) void WorldSession::HandleChannelAnnouncementsOpcode(WorldPacket& recvPacket)
@ -296,7 +297,7 @@ void WorldSession::HandleChannelAnnouncementsOpcode(WorldPacket& recvPacket)
std::string channelname = recvPacket.ReadString(recvPacket.ReadBits(8)); std::string channelname = recvPacket.ReadString(recvPacket.ReadBits(8));
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetChannel(channelname, _player)) if (Channel* chn = cMgr->GetChannel(channelname, _player))
chn->Announce(_player->GetObjectGuid()); chn->Announce(_player);
} }
void WorldSession::HandleChannelModerateOpcode(WorldPacket& recvPacket) void WorldSession::HandleChannelModerateOpcode(WorldPacket& recvPacket)
@ -307,7 +308,7 @@ void WorldSession::HandleChannelModerateOpcode(WorldPacket& recvPacket)
recvPacket >> channelname; recvPacket >> channelname;
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetChannel(channelname, _player)) if (Channel* chn = cMgr->GetChannel(channelname, _player))
chn->Moderate(_player->GetObjectGuid()); chn->Moderate(_player);
} }
void WorldSession::HandleChannelDisplayListQueryOpcode(WorldPacket& recvPacket) void WorldSession::HandleChannelDisplayListQueryOpcode(WorldPacket& recvPacket)

View file

@ -537,6 +537,7 @@ ChatCommand* ChatHandler::getCommandTable()
{ "creature_ai_summons", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAISummonsCommand, "", NULL }, { "creature_ai_summons", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAISummonsCommand, "", NULL },
{ "creature_ai_texts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAITextsCommand, "", NULL }, { "creature_ai_texts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAITextsCommand, "", NULL },
{ "creature_battleground", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadBattleEventCommand, "", NULL }, { "creature_battleground", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadBattleEventCommand, "", NULL },
{ "creature_template_classlevelstats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreaturesStatsCommand, "", nullptr },
{ "creature_involvedrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestInvRelationsCommand, "", NULL }, { "creature_involvedrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestInvRelationsCommand, "", NULL },
{ "creature_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesCreatureCommand, "", NULL }, { "creature_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesCreatureCommand, "", NULL },
{ "creature_questrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestRelationsCommand, "", NULL }, { "creature_questrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestRelationsCommand, "", NULL },
@ -985,7 +986,7 @@ void ChatHandler::SendSysMessage(const char* str)
while (char* line = LineFromMessage(pos)) while (char* line = LineFromMessage(pos))
{ {
FillSystemMessageData(&data, line); ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, line, LANG_UNIVERSAL, CHAT_TAG_NONE, m_session->GetPlayer()->GetObjectGuid());
m_session->SendPacket(&data); m_session->SendPacket(&data);
} }
@ -1000,10 +1001,11 @@ void ChatHandler::SendGlobalSysMessage(const char* str)
// need copy to prevent corruption by strtok call in LineFromMessage original string // need copy to prevent corruption by strtok call in LineFromMessage original string
char* buf = mangos_strdup(str); char* buf = mangos_strdup(str);
char* pos = buf; char* pos = buf;
ObjectGuid guid = m_session ? m_session->GetPlayer()->GetObjectGuid() : ObjectGuid();
while (char* line = LineFromMessage(pos)) while (char* line = LineFromMessage(pos))
{ {
FillSystemMessageData(&data, line); ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, line, LANG_UNIVERSAL, CHAT_TAG_NONE, guid);
sWorld.SendGlobalMessage(&data); sWorld.SendGlobalMessage(&data);
} }
@ -2095,99 +2097,6 @@ bool ChatHandler::isValidChatMessage(const char* message)
return validSequence == validSequenceIterator; return validSequence == validSequenceIterator;
} }
// Note: target_guid used only in CHAT_MSG_WHISPER_INFORM mode (in this case channelName ignored)
void ChatHandler::FillMessageData(WorldPacket* data, WorldSession* session, uint8 type, uint32 language, const char* channelName, ObjectGuid targetGuid, const char* message, Unit* speaker, const char* addonPrefix /*= NULL*/)
{
uint32 messageLength = (message ? strlen(message) : 0) + 1;
data->Initialize(SMSG_MESSAGECHAT, 100); // guess size
*data << uint8(type);
if ((type != CHAT_MSG_CHANNEL && type != CHAT_MSG_WHISPER) || language == LANG_ADDON)
*data << uint32(language);
else
*data << uint32(LANG_UNIVERSAL);
switch (type)
{
case CHAT_MSG_SAY:
case CHAT_MSG_PARTY:
case CHAT_MSG_PARTY_LEADER:
case CHAT_MSG_RAID:
case CHAT_MSG_GUILD:
case CHAT_MSG_OFFICER:
case CHAT_MSG_YELL:
case CHAT_MSG_WHISPER:
case CHAT_MSG_CHANNEL:
case CHAT_MSG_RAID_LEADER:
case CHAT_MSG_RAID_WARNING:
case CHAT_MSG_BG_SYSTEM_NEUTRAL:
case CHAT_MSG_BG_SYSTEM_ALLIANCE:
case CHAT_MSG_BG_SYSTEM_HORDE:
case CHAT_MSG_BATTLEGROUND:
case CHAT_MSG_BATTLEGROUND_LEADER:
targetGuid = session ? session->GetPlayer()->GetObjectGuid() : ObjectGuid();
break;
case CHAT_MSG_MONSTER_SAY:
case CHAT_MSG_MONSTER_PARTY:
case CHAT_MSG_MONSTER_YELL:
case CHAT_MSG_MONSTER_WHISPER:
case CHAT_MSG_MONSTER_EMOTE:
case CHAT_MSG_RAID_BOSS_WHISPER:
case CHAT_MSG_RAID_BOSS_EMOTE:
case CHAT_MSG_BATTLENET:
{
*data << ObjectGuid(speaker->GetObjectGuid());
*data << uint32(0); // 2.1.0
*data << uint32(strlen(speaker->GetName()) + 1);
*data << speaker->GetName();
ObjectGuid listener_guid;
*data << listener_guid;
if (listener_guid && !listener_guid.IsPlayer())
{
*data << uint32(1); // string listener_name_length
*data << uint8(0); // string listener_name
}
*data << uint32(messageLength);
*data << message;
*data << uint8(0);
if (type == CHAT_MSG_RAID_BOSS_WHISPER || type == CHAT_MSG_RAID_BOSS_EMOTE)
{
*data << float(0.0f); // Added in 4.2.0, unk
*data << uint8(0); // Added in 4.2.0, unk
}
return;
}
default:
if (type != CHAT_MSG_WHISPER_INFORM && type != CHAT_MSG_IGNORED && type != CHAT_MSG_DND && type != CHAT_MSG_AFK)
targetGuid.Clear(); // only for CHAT_MSG_WHISPER_INFORM used original value target_guid
break;
}
*data << ObjectGuid(targetGuid); // there 0 for BG messages
*data << uint32(0); // can be chat msg group or something
if (type == CHAT_MSG_CHANNEL)
{
MANGOS_ASSERT(channelName);
*data << channelName;
*data << ObjectGuid(targetGuid);
}
else if (type == CHAT_MSG_ADDON)
{
MANGOS_ASSERT(addonPrefix);
*data << addonPrefix;
}
else
*data << ObjectGuid(targetGuid);
*data << uint32(messageLength);
*data << message;
if (session != 0 && type != CHAT_MSG_WHISPER_INFORM && type != CHAT_MSG_DND && type != CHAT_MSG_AFK)
*data << uint8(session->GetPlayer()->GetChatTag());
else
*data << uint8(0);
}
Player* ChatHandler::getSelectedPlayer() Player* ChatHandler::getSelectedPlayer()
{ {
if (!m_session) if (!m_session)
@ -3717,11 +3626,12 @@ void ChatHandler::LogCommand(char const* fullcmd)
} }
void ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg msgtype, char const* message, Language language /*= LANG_UNIVERSAL*/, ChatTagFlags chatTag /*= CHAT_TAG_NONE*/, void ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg msgtype, char const* message, Language language /*= LANG_UNIVERSAL*/, ChatTagFlags chatTag /*= CHAT_TAG_NONE*/,
ObjectGuid const& senderGuid /*= ObjectGuid()*/, char const* senderName /*= NULL*/, ObjectGuid const& senderGuid /*= ObjectGuid()*/, char const* senderName /*= nullptr*/,
ObjectGuid const& targetGuid /*= ObjectGuid()*/, char const* targetName /*= NULL*/, ObjectGuid const& targetGuid /*= ObjectGuid()*/, char const* targetName /*= nullptr*/,
char const* channelName /*= NULL*/) char const* channelName /*= nullptr*/, uint32 achievementId /*= 0*/, const char* addonPrefix /*= nullptr*/)
{ {
bool isGM = chatTag & CHAT_TAG_GM; bool isGM = chatTag & CHAT_TAG_GM;
bool isAchievement = false;
data.Initialize(isGM ? SMSG_GM_MESSAGECHAT : SMSG_MESSAGECHAT); data.Initialize(isGM ? SMSG_GM_MESSAGECHAT : SMSG_MESSAGECHAT);
data << uint8(msgtype); data << uint8(msgtype);
@ -3735,22 +3645,20 @@ void ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg msgtype, char const
case CHAT_MSG_MONSTER_PARTY: case CHAT_MSG_MONSTER_PARTY:
case CHAT_MSG_MONSTER_YELL: case CHAT_MSG_MONSTER_YELL:
case CHAT_MSG_MONSTER_WHISPER: case CHAT_MSG_MONSTER_WHISPER:
case CHAT_MSG_MONSTER_EMOTE:
case CHAT_MSG_RAID_BOSS_WHISPER: case CHAT_MSG_RAID_BOSS_WHISPER:
case CHAT_MSG_RAID_BOSS_EMOTE: case CHAT_MSG_RAID_BOSS_EMOTE:
case CHAT_MSG_MONSTER_EMOTE: case CHAT_MSG_BATTLENET:
case CHAT_MSG_WHISPER_FOREIGN:
MANGOS_ASSERT(senderName); MANGOS_ASSERT(senderName);
data << uint32(strlen(senderName) + 1); data << uint32(strlen(senderName) + 1);
data << senderName; data << senderName;
data << ObjectGuid(targetGuid); // Unit Target data << ObjectGuid(targetGuid); // Unit Target
if (targetGuid && !targetGuid.IsPlayer() && !targetGuid.IsPet()) if (targetGuid && !targetGuid.IsPlayer() && !targetGuid.IsPet() && (msgtype != CHAT_MSG_WHISPER_FOREIGN))
{ {
data << uint32(strlen(targetName) + 1); // target name length data << uint32(strlen(targetName) + 1); // target name length
data << targetName; // target name data << targetName; // target name
} }
MANGOS_ASSERT(message);
data << uint32(strlen(message) + 1);
data << message;
data << uint8(chatTag);
break; break;
case CHAT_MSG_BG_SYSTEM_NEUTRAL: case CHAT_MSG_BG_SYSTEM_NEUTRAL:
case CHAT_MSG_BG_SYSTEM_ALLIANCE: case CHAT_MSG_BG_SYSTEM_ALLIANCE:
@ -3762,30 +3670,48 @@ void ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg msgtype, char const
data << uint32(strlen(targetName) + 1); // target name length data << uint32(strlen(targetName) + 1); // target name length
data << targetName; // target name data << targetName; // target name
} }
MANGOS_ASSERT(message); break;
data << uint32(strlen(message) + 1); case CHAT_MSG_ACHIEVEMENT:
data << message; case CHAT_MSG_GUILD_ACHIEVEMENT:
data << uint8(chatTag); data << ObjectGuid(targetGuid); // Unit Target
isAchievement = true;
break; break;
default: default:
if (msgtype == CHAT_MSG_CHANNEL)
{
MANGOS_ASSERT(channelName);
data << channelName;
}
data << ObjectGuid(targetGuid);
MANGOS_ASSERT(message);
data << uint32(strlen(message) + 1);
data << message;
data << uint8(chatTag);
if (isGM) if (isGM)
{ {
MANGOS_ASSERT(senderName); MANGOS_ASSERT(senderName);
data << uint32(strlen(senderName) + 1); data << uint32(strlen(senderName) + 1);
data << senderName; data << senderName;
} }
if (msgtype == CHAT_MSG_CHANNEL)
{
MANGOS_ASSERT(channelName);
data << channelName;
data << ObjectGuid(targetGuid);
}
else if (msgtype == CHAT_MSG_ADDON)
{
MANGOS_ASSERT(addonPrefix);
data << addonPrefix;
}
else
data << ObjectGuid(targetGuid);
break; break;
} }
MANGOS_ASSERT(message);
data << uint32(strlen(message) + 1);
data << message;
data << uint8(chatTag);
if (isAchievement)
data << uint32(achievementId);
if (msgtype == CHAT_MSG_RAID_BOSS_WHISPER || msgtype == CHAT_MSG_RAID_BOSS_EMOTE)
{
data << float(0.0f); // Added in 4.2.0, unk
data << uint8(0); // Added in 4.2.0, unk
}
} }
// Instantiate template for helper function // Instantiate template for helper function

View file

@ -71,12 +71,12 @@ enum ChatCommandSearchResult
enum PlayerChatTag enum PlayerChatTag
{ {
CHAT_TAG_NONE = 0, CHAT_TAG_NONE = 0x00,
CHAT_TAG_AFK = 1, CHAT_TAG_AFK = 0x01,
CHAT_TAG_DND = 2, CHAT_TAG_DND = 0x02,
CHAT_TAG_GM = 3, CHAT_TAG_GM = 0x04,
CHAT_TAG_COM = 4, // Commentator CHAT_TAG_COM = 0x08, // Commentator
CHAT_TAG_DEV = 5, // Developer CHAT_TAG_DEV = 0x10, // Developer
}; };
typedef uint32 ChatTagFlags; typedef uint32 ChatTagFlags;
@ -87,23 +87,6 @@ class ChatHandler
explicit ChatHandler(Player* player); explicit ChatHandler(Player* player);
~ChatHandler(); ~ChatHandler();
static void FillMessageData(WorldPacket* data, WorldSession* session, uint8 type, uint32 language, const char* channelName, ObjectGuid targetGuid, const char* message, Unit* speaker, const char* addonPrefix = NULL);
static void FillMessageData(WorldPacket* data, WorldSession* session, uint8 type, uint32 language, ObjectGuid targetGuid, const char* message)
{
FillMessageData(data, session, type, language, NULL, targetGuid, message, NULL);
}
static void FillMessageData(WorldPacket* data, WorldSession* session, uint8 type, uint32 language, const char* message)
{
FillMessageData(data, session, type, language, NULL, ObjectGuid(), message, NULL);
}
void FillSystemMessageData(WorldPacket* data, const char* message)
{
FillMessageData(data, m_session, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, ObjectGuid(), message);
}
static char* LineFromMessage(char*& pos) { char* start = strtok(pos, "\n"); pos = NULL; return start; } static char* LineFromMessage(char*& pos) { char* start = strtok(pos, "\n"); pos = NULL; return start; }
// function with different implementation for chat/console // function with different implementation for chat/console
@ -140,12 +123,13 @@ class ChatHandler
* \param ObjectGuid const& targetGuid : Often null, but needed for type *MONSTER* or *BATTLENET or *BATTLEGROUND* or *ACHIEVEMENT * \param ObjectGuid const& targetGuid : Often null, but needed for type *MONSTER* or *BATTLENET or *BATTLEGROUND* or *ACHIEVEMENT
* \param char const* targetName : Often null, but needed for type *MONSTER* or *BATTLENET or *BATTLEGROUND* * \param char const* targetName : Often null, but needed for type *MONSTER* or *BATTLENET or *BATTLEGROUND*
* \param char const* channelName : Required only for CHAT_MSG_CHANNEL * \param char const* channelName : Required only for CHAT_MSG_CHANNEL
* \param uint32 achievementId : Required only for *ACHIEVEMENT
* \param const char* addonPrefix : Required only for *CHAT_MSG_ADDON
**/ **/
static void BuildChatPacket( static void ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg msgtype, char const* message, Language language = LANG_UNIVERSAL, ChatTagFlags chatTag = CHAT_TAG_NONE,
WorldPacket& data, ChatMsg msgtype, char const* message, Language language = LANG_UNIVERSAL, ChatTagFlags chatTag = CHAT_TAG_NONE,
ObjectGuid const& senderGuid = ObjectGuid(), char const* senderName = NULL, ObjectGuid const& senderGuid = ObjectGuid(), char const* senderName = NULL,
ObjectGuid const& targetGuid = ObjectGuid(), char const* targetName = NULL, ObjectGuid const& targetGuid = ObjectGuid(), char const* targetName = NULL,
char const* channelName = NULL); char const* channelName = NULL, uint32 achievementId = 0, const char* addonPrefix = NULL);
protected: protected:
explicit ChatHandler() : m_session(NULL) {} // for CLI subclass explicit ChatHandler() : m_session(NULL) {} // for CLI subclass
@ -450,6 +434,7 @@ class ChatHandler
bool HandleReloadAreaTriggerTavernCommand(char* args); bool HandleReloadAreaTriggerTavernCommand(char* args);
bool HandleReloadAreaTriggerTeleportCommand(char* args); bool HandleReloadAreaTriggerTeleportCommand(char* args);
bool HandleReloadBattleEventCommand(char* args); bool HandleReloadBattleEventCommand(char* args);
bool HandleReloadCreaturesStatsCommand(char* args);
bool HandleReloadCommandCommand(char* args); bool HandleReloadCommandCommand(char* args);
bool HandleReloadConditionsCommand(char* args); bool HandleReloadConditionsCommand(char* args);
bool HandleReloadCreatureQuestRelationsCommand(char* args); bool HandleReloadCreatureQuestRelationsCommand(char* args);

View file

@ -286,7 +286,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data)
return; return;
WorldPacket data; WorldPacket data;
ChatHandler::FillMessageData(&data, this, type, lang, msg.c_str()); ChatHandler::BuildChatPacket(data, ChatMsg(type), msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName());
group->BroadcastPacket(&data, false, group->GetMemberGroup(GetPlayer()->GetObjectGuid())); group->BroadcastPacket(&data, false, group->GetMemberGroup(GetPlayer()->GetObjectGuid()));
break; break;
@ -364,7 +364,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data)
} }
WorldPacket data; WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, msg.c_str()); ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID, msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName());
group->BroadcastPacket(&data, false); group->BroadcastPacket(&data, false);
} break; } break;
case CHAT_MSG_RAID_LEADER: case CHAT_MSG_RAID_LEADER:
@ -394,7 +394,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data)
} }
WorldPacket data; WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, msg.c_str()); ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID_LEADER, msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName());
group->BroadcastPacket(&data, false); group->BroadcastPacket(&data, false);
} break; } break;
@ -416,7 +416,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data)
WorldPacket data; WorldPacket data;
// in battleground, raid warning is sent only to players in battleground - code is ok // in battleground, raid warning is sent only to players in battleground - code is ok
ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, msg.c_str()); ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID_WARNING, msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName());
group->BroadcastPacket(&data, false); group->BroadcastPacket(&data, false);
} break; } break;
@ -437,7 +437,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data)
return; return;
WorldPacket data; WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, msg.c_str()); ChatHandler::BuildChatPacket(data, CHAT_MSG_BATTLEGROUND, msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName());
group->BroadcastPacket(&data, false); group->BroadcastPacket(&data, false);
} break; } break;
@ -458,7 +458,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data)
return; return;
WorldPacket data; WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, msg.c_str()); ChatHandler::BuildChatPacket(data, CHAT_MSG_BATTLEGROUND_LEADER, msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName());
group->BroadcastPacket(&data, false); group->BroadcastPacket(&data, false);
} break; } break;
@ -478,7 +478,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data)
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetChannel(channel, _player)) if (Channel* chn = cMgr->GetChannel(channel, _player))
chn->Say(_player->GetObjectGuid(), msg.c_str(), lang); chn->Say(_player, msg.c_str(), lang);
} break; } break;
case CHAT_MSG_AFK: case CHAT_MSG_AFK:
@ -539,7 +539,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data)
void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recv_data) void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recv_data)
{ {
uint32 type; ChatMsg type;
switch (recv_data.GetOpcode()) switch (recv_data.GetOpcode())
{ {
@ -573,7 +573,7 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recv_data)
return; return;
WorldPacket data; WorldPacket data;
ChatHandler::FillMessageData(&data, this, type, LANG_ADDON, "", ObjectGuid(), msg.c_str(), NULL); ChatHandler::BuildChatPacket(data, type, msg.c_str(), LANG_ADDON);
group->BroadcastPacket(&data, false); group->BroadcastPacket(&data, false);
break; break;
} }
@ -618,7 +618,9 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recv_data)
if (!receiver) if (!receiver)
break; break;
_player->WhisperAddon(msg, prefix, receiver->GetObjectGuid()); WorldPacket data;
ChatHandler::BuildChatPacket(data, type, msg.c_str(), LANG_UNIVERSAL, CHAT_TAG_NONE, ObjectGuid(), NULL, receiver->GetObjectGuid(), targetName.c_str(), NULL, 0, prefix.c_str());
_player->GetSession()->SendPacket(&data);
break; break;
} }
// Messages sent to "RAID" while in a party will get delivered to "PARTY" // Messages sent to "RAID" while in a party will get delivered to "PARTY"
@ -635,7 +637,7 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recv_data)
break; break;
WorldPacket data; WorldPacket data;
ChatHandler::FillMessageData(&data, this, type, LANG_ADDON, "", ObjectGuid(), msg.c_str(), NULL, prefix.c_str()); ChatHandler::BuildChatPacket(data, type, msg.c_str(), LANG_ADDON, CHAT_TAG_NONE, ObjectGuid(), NULL, ObjectGuid(), NULL, NULL, 0, prefix.c_str());
group->BroadcastPacket(&data, false, group->GetMemberGroup(_player->GetObjectGuid())); group->BroadcastPacket(&data, false, group->GetMemberGroup(_player->GetObjectGuid()));
break; break;
} }
@ -768,7 +770,7 @@ void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data)
return; return;
WorldPacket data; WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_IGNORED, LANG_UNIVERSAL, NULL, GetPlayer()->GetObjectGuid(), GetPlayer()->GetName(), NULL); ChatHandler::BuildChatPacket(data, CHAT_MSG_IGNORED, _player->GetName(), LANG_UNIVERSAL, CHAT_TAG_NONE, _player->GetObjectGuid());
player->GetSession()->SendPacket(&data); player->GetSession()->SendPacket(&data);
} }

View file

@ -32,7 +32,7 @@
class WorldSession; class WorldSession;
#define GOSSIP_MAX_MENU_ITEMS 64 // client supported items unknown, but provided number must be enough #define GOSSIP_MAX_MENU_ITEMS 32 // client supports showing max 32 items
#define DEFAULT_GOSSIP_MESSAGE 0xffffff #define DEFAULT_GOSSIP_MESSAGE 0xffffff
enum Gossip_Option enum Gossip_Option

View file

@ -657,7 +657,7 @@ void MaNGOS::LocalizedPacketDo<Builder>::operator()(Player* p)
if (i_data_cache.size() < cache_idx + 1) if (i_data_cache.size() < cache_idx + 1)
i_data_cache.resize(cache_idx + 1); i_data_cache.resize(cache_idx + 1);
data = new WorldPacket(SMSG_MESSAGECHAT, 200); data = new WorldPacket();
i_builder(*data, loc_idx); i_builder(*data, loc_idx);

View file

@ -45,6 +45,7 @@
#include "BattleGround/BattleGroundMgr.h" #include "BattleGround/BattleGroundMgr.h"
#include "Weather.h" #include "Weather.h"
#include "Calendar.h" #include "Calendar.h"
#include "Chat.h"
#ifdef ENABLE_ELUNA #ifdef ENABLE_ELUNA
#include "LuaEngine.h" #include "LuaEngine.h"
#endif /* ENABLE_ELUNA */ #endif /* ENABLE_ELUNA */
@ -1971,7 +1972,7 @@ uint32 Map::GenerateLocalLowGuid(HighGuid guidhigh)
class StaticMonsterChatBuilder class StaticMonsterChatBuilder
{ {
public: public:
StaticMonsterChatBuilder(CreatureInfo const* cInfo, ChatMsg msgtype, int32 textId, uint32 language, Unit const* target, uint32 senderLowGuid = 0) StaticMonsterChatBuilder(CreatureInfo const* cInfo, ChatMsg msgtype, int32 textId, Language language, Unit const* target, uint32 senderLowGuid = 0)
: i_cInfo(cInfo), i_msgtype(msgtype), i_textId(textId), i_language(language), i_target(target) : i_cInfo(cInfo), i_msgtype(msgtype), i_textId(textId), i_language(language), i_target(target)
{ {
// 0 lowguid not used in core, but accepted fine in this case by client // 0 lowguid not used in core, but accepted fine in this case by client
@ -1984,7 +1985,8 @@ class StaticMonsterChatBuilder
char const* nameForLocale = i_cInfo->Name; char const* nameForLocale = i_cInfo->Name;
sObjectMgr.GetCreatureLocaleStrings(i_cInfo->Entry, loc_idx, &nameForLocale); sObjectMgr.GetCreatureLocaleStrings(i_cInfo->Entry, loc_idx, &nameForLocale);
WorldObject::BuildMonsterChat(&data, i_senderGuid, i_msgtype, text, i_language, nameForLocale, i_target ? i_target->GetObjectGuid() : ObjectGuid(), i_target ? i_target->GetNameForLocaleIdx(loc_idx) : ""); ChatHandler::BuildChatPacket(data, i_msgtype, text, i_language, CHAT_TAG_NONE, i_senderGuid, nameForLocale, i_target ? i_target->GetObjectGuid() : ObjectGuid(),
i_target ? i_target->GetNameForLocaleIdx(loc_idx) : "");
} }
private: private:
@ -1992,7 +1994,7 @@ class StaticMonsterChatBuilder
CreatureInfo const* i_cInfo; CreatureInfo const* i_cInfo;
ChatMsg i_msgtype; ChatMsg i_msgtype;
int32 i_textId; int32 i_textId;
uint32 i_language; Language i_language;
Unit const* i_target; Unit const* i_target;
}; };
@ -2126,3 +2128,178 @@ bool Map::ContainsGameObjectModel(const GameObjectModel& mdl) const
{ {
return m_dyn_tree.contains(mdl); return m_dyn_tree.contains(mdl);
} }
// This will generate a random point to all directions in water for the provided point in radius range.
bool Map::GetRandomPointUnderWater(uint32 phaseMask, float& x, float& y, float& z, float radius, GridMapLiquidData& liquid_status)
{
const float angle = rand_norm_f() * (M_PI_F * 2.0f);
const float range = rand_norm_f() * radius;
float i_x = x + range * cos(angle);
float i_y = y + range * sin(angle);
// get real ground of new point
// the code consider cylinder instead of sphere for possible z
float ground = GetHeight(phaseMask, i_x, i_y, z);
if (ground > INVALID_HEIGHT) // GetHeight can fail
{
float min_z = z - 0.7f * radius; // 0.7 to have a bit a "flat" cylinder, TODO which value looks nicest
if (min_z < ground)
min_z = ground + 0.5f; // Get some space to prevent under map
float liquidLevel = liquid_status.level - 2.0f; // just to make the generated point is in water and not on surface or a bit above
// if not enough space to fit the creature better is to return from here
if (min_z > liquidLevel)
return false;
float max_z = std::max(z + 0.7f * radius, min_z);
max_z = std::min(max_z, liquidLevel);
x = i_x;
y = i_y;
z = min_z + rand_norm_f() * (max_z - min_z);
return true;
}
return false;
}
// This will generate a random point to all directions in air for the provided point in radius range.
bool Map::GetRandomPointInTheAir(uint32 phaseMask, float& x, float& y, float& z, float radius)
{
const float angle = rand_norm_f() * (M_PI_F * 2.0f);
const float range = rand_norm_f() * radius;
float i_x = x + range * cos(angle);
float i_y = y + range * sin(angle);
// get real ground of new point
// the code consider cylinder instead of sphere for possible z
float ground = GetHeight(phaseMask, i_x, i_y, z);
if (ground > INVALID_HEIGHT) // GetHeight can fail
{
float min_z = z - 0.7f * radius; // 0.7 to have a bit a "flat" cylinder, TODO which value looks nicest
if (min_z < ground)
min_z = ground + 2.5f; // Get some space to prevent landing
float max_z = std::max(z + 0.7f * radius, min_z);
x = i_x;
y = i_y;
z = min_z + rand_norm_f() * (max_z - min_z);
return true;
}
return false;
}
// supposed to be used for not big radius, usually less than 20.0f
bool Map::GetReachableRandomPointOnGround(uint32 phaseMask, float& x, float& y, float& z, float radius)
{
// Generate a random range and direction for the new point
const float angle = rand_norm_f() * (M_PI_F * 2.0f);
const float range = rand_norm_f() * radius;
float i_x = x + range * cos(angle);
float i_y = y + range * sin(angle);
float i_z = z + 1.0f;
GetHitPosition(x, y, z + 1.0f, i_x, i_y, i_z, phaseMask, -0.5f);
i_z = z; // reset i_z to z value to avoid too much difference from original point before GetHeightInRange
// commented out, as this function has not been defined anywhere (previous cores or other repos)
// if (!GetHeightInRange(phaseMask, i_x, i_y, i_z)) // GetHeight can fail
// return false;
// here we have a valid position but the point can have a big Z in some case
// next code will check angle from 2 points
// c
// /|
// / |
// b/__|a
// project vector to get only positive value
float ab = fabs(x - i_x);
float ac = fabs(z - i_z);
// slope represented by c angle (in radian)
float slope = 0;
const float MAX_SLOPE_IN_RADIAN = 50.0f / 180.0f * M_PI_F; // 50(degree) max seem best value for walkable slope
// check ab vector to avoid divide by 0
if (ab > 0.0f)
{
// compute c angle and convert it from radian to degree
slope = atan(ac / ab);
if (slope < MAX_SLOPE_IN_RADIAN)
{
x = i_x;
y = i_y;
z = i_z;
return true;
}
}
return false;
}
// Get random point by handling different situation depending of if the unit is flying/swimming/walking
bool Map::GetReachableRandomPosition(Unit* unit, float& x, float& y, float& z, float radius)
{
float i_x = x;
float i_y = y;
float i_z = z;
bool newDestAssigned = false; // used to check if new random destination is found
bool isFlying = false;
bool isSwimming = true;
switch (unit->GetTypeId())
{
case TYPEID_PLAYER:
isFlying = static_cast<Player*>(unit)->IsFlying();
break;
case TYPEID_UNIT:
isFlying = static_cast<Creature*>(unit)->IsFlying();
isSwimming = static_cast<Creature*>(unit)->IsSwimming();
break;
default:
sLog.outError("Map::GetReachableRandomPosition> Unsupported unit type is passed!");
return false;
}
if (radius < 0.1f)
{
sLog.outError("Map::GetReachableRandomPosition> Unsupported unit type is passed!");
return false;
}
if (isFlying)
{
newDestAssigned = GetRandomPointInTheAir(unit->GetPhaseMask(), i_x, i_y, i_z, radius);
/*if (newDestAssigned)
sLog.outString("Generating air random point for %s", GetGuidStr().c_str());*/
}
else
{
GridMapLiquidData liquid_status;
GridMapLiquidStatus res = m_TerrainData->getLiquidStatus(i_x, i_y, i_z, MAP_ALL_LIQUIDS, &liquid_status);
if (isSwimming && (res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER)))
{
newDestAssigned = GetRandomPointUnderWater(unit->GetPhaseMask(), i_x, i_y, i_z, radius, liquid_status);
/*if (newDestAssigned)
sLog.outString("Generating swim random point for %s", GetGuidStr().c_str());*/
}
else
{
newDestAssigned = GetReachableRandomPointOnGround(unit->GetPhaseMask(), i_x, i_y, i_z, radius);
/*if (newDestAssigned)
sLog.outString("Generating ground random point for %s", GetGuidStr().c_str());*/
}
}
if (newDestAssigned)
{
x = i_x;
y = i_y;
z = i_z;
return true;
}
return false;
}

View file

@ -309,9 +309,9 @@ class Map : public GridRefManager<NGridType>
// Random on map generation // Random on map generation
bool GetReachableRandomPosition(Unit* unit, float& x, float& y, float& z, float radius); bool GetReachableRandomPosition(Unit* unit, float& x, float& y, float& z, float radius);
bool GetReachableRandomPointOnGround(float& x, float& y, float& z, float radius); bool GetReachableRandomPointOnGround(uint32 phaseMask, float& x, float& y, float& z, float radius);
bool GetRandomPointInTheAir(float& x, float& y, float& z, float radius); bool GetRandomPointInTheAir(uint32 phaseMask, float& x, float& y, float& z, float radius);
bool GetRandomPointUnderWater(float& x, float& y, float& z, float radius, GridMapLiquidData& liquid_status); bool GetRandomPointUnderWater(uint32 phaseMask, float& x, float& y, float& z, float radius, GridMapLiquidData& liquid_status);
private: private:
void LoadMapAndVMap(int gx, int gy); void LoadMapAndVMap(int gx, int gy);

View file

@ -1565,7 +1565,7 @@ void WorldSession::HandleRequestHotfix(WorldPacket& recv_data)
count = recv_data.ReadBits(23); count = recv_data.ReadBits(23);
std::vector<ObjectGuid> guids; std::vector<ObjectGuid> guids;
guids.reserve(count); guids.resize(count);
for (uint32 i = 0; i < count; ++i) for (uint32 i = 0; i < count; ++i)
recv_data.ReadGuidMask<0, 4, 7, 2, 5, 3, 6, 1>(guids[i]); recv_data.ReadGuidMask<0, 4, 7, 2, 5, 3, 6, 1>(guids[i]);

View file

@ -178,12 +178,12 @@ void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle)
} }
uint32 maxcount = (cSpells ? cSpells->spellList.size() : 0) + (tSpells ? tSpells->spellList.size() : 0); uint32 maxcount = (cSpells ? cSpells->spellList.size() : 0) + (tSpells ? tSpells->spellList.size() : 0);
uint32 trainer_type = cSpells && cSpells->trainerType ? cSpells->trainerType : (tSpells ? tSpells->trainerType : 0); uint32 TrainerType = cSpells && cSpells->trainerType ? cSpells->trainerType : (tSpells ? tSpells->trainerType : 0);
WorldPacket data(SMSG_TRAINER_LIST, 8 + 4 + 4 + maxcount * 38 + strTitle.size() + 1); WorldPacket data(SMSG_TRAINER_LIST, 8 + 4 + 4 + maxcount * 38 + strTitle.size() + 1);
data << ObjectGuid(guid); data << ObjectGuid(guid);
data << uint32(trainer_type); data << uint32(TrainerType);
data << uint32(ci->trainerId); data << uint32(ci->TrainerTemplateId);
size_t count_pos = data.wpos(); size_t count_pos = data.wpos();
data << uint32(maxcount); data << uint32(maxcount);
@ -243,9 +243,9 @@ void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle)
void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recv_data) void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recv_data)
{ {
ObjectGuid guid; ObjectGuid guid;
uint32 spellId = 0, trainerId = 0; uint32 spellId = 0, TrainerTemplateId = 0;
recv_data >> guid >> trainerId >> spellId; recv_data >> guid >> TrainerTemplateId >> spellId;
DEBUG_LOG("WORLD: Received opcode CMSG_TRAINER_BUY_SPELL Trainer: %s, learn spell id is: %u", guid.GetString().c_str(), spellId); DEBUG_LOG("WORLD: Received opcode CMSG_TRAINER_BUY_SPELL Trainer: %s, learn spell id is: %u", guid.GetString().c_str(), spellId);
Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER);

View file

@ -182,8 +182,8 @@ void WorldSession::HandleCreatureQueryOpcode(WorldPacket& recv_data)
data << ci->IconName; // "Directions" for guard, string for Icons 2.3.0 data << ci->IconName; // "Directions" for guard, string for Icons 2.3.0
data << uint32(ci->CreatureTypeFlags); // flags data << uint32(ci->CreatureTypeFlags); // flags
data << uint32(0); // unk data << uint32(0); // unk
data << uint32(ci->type); // CreatureType.dbc data << uint32(ci->CreatureType); // CreatureType.dbc
data << uint32(ci->family); // CreatureFamily.dbc data << uint32(ci->Family); // CreatureFamily.dbc
data << uint32(ci->Rank); // Creature Rank (elite, boss, etc) data << uint32(ci->Rank); // Creature Rank (elite, boss, etc)
data << uint32(ci->KillCredit[0]); // new in 3.1, kill credit data << uint32(ci->KillCredit[0]); // new in 3.1, kill credit
data << uint32(ci->KillCredit[1]); // new in 3.1, kill credit data << uint32(ci->KillCredit[1]); // new in 3.1, kill credit
@ -191,12 +191,12 @@ void WorldSession::HandleCreatureQueryOpcode(WorldPacket& recv_data)
for (int i = 0; i < MAX_CREATURE_MODEL; ++i) for (int i = 0; i < MAX_CREATURE_MODEL; ++i)
data << uint32(ci->ModelId[i]); data << uint32(ci->ModelId[i]);
data << float(ci->healthModifier); // health modifier data << float(ci->HealthMultiplier); // health modifier
data << float(ci->powerModifier); // power modifier data << float(ci->PowerMultiplier); // power modifier
data << uint8(ci->RacialLeader); data << uint8(ci->RacialLeader);
for (uint32 i = 0; i < 6; ++i) for (uint32 i = 0; i < 6; ++i)
data << uint32(ci->questItems[i]); // itemId[6], quest drop data << uint32(ci->QuestItems[i]); // itemId[6], quest drop
data << uint32(ci->movementId); // CreatureMovementInfo.dbc data << uint32(ci->MovementTemplateId); // CreatureMovementInfo.dbc
data << uint32(0); //unk data << uint32(0); //unk
SendPacket(&data); SendPacket(&data);
DEBUG_LOG("WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE"); DEBUG_LOG("WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE");

View file

@ -1226,7 +1226,7 @@ bool ScriptAction::HandleScriptStep()
for (int i = 0; i < MAX_TEXT_ID; ++i) for (int i = 0; i < MAX_TEXT_ID; ++i)
{ {
if (!m_script->textId[i]) if (!m_script->textId[i])
{ break; } break;
emotes.push_back(uint32(m_script->textId[i])); emotes.push_back(uint32(m_script->textId[i]));
} }

View file

@ -3384,7 +3384,7 @@ void Spell::cast(bool skipCheck)
// Hand of Reckoning // Hand of Reckoning
else if (m_spellInfo->Id == 62124) else if (m_spellInfo->Id == 62124)
{ {
if (m_targets.getUnitTarget() && m_targets.getUnitTarget()->getVictim() != m_caster) if (!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetTargetGuid() != m_caster->GetObjectGuid())
AddPrecastSpell(67485); // Hand of Rekoning (no typos in name ;) ) AddPrecastSpell(67485); // Hand of Rekoning (no typos in name ;) )
} }
// Divine Shield, Divine Protection or Hand of Protection // Divine Shield, Divine Protection or Hand of Protection
@ -7972,6 +7972,7 @@ void Spell::GetSpellRangeAndRadius(SpellEffectEntry const* spellEffect, float& r
case 44869: // Spectral Blast (SWP, Kalecgos) case 44869: // Spectral Blast (SWP, Kalecgos)
case 45391: // Summon Demonic Vapor (SWP, Felmyst) case 45391: // Summon Demonic Vapor (SWP, Felmyst)
case 45785: // Sinister Reflection Clone (SWP, Kil'jaeden) case 45785: // Sinister Reflection Clone (SWP, Kil'jaeden)
case 45863: // Cosmetic - Incinerate to Random Target (Borean Tundra)
case 45892: // Sinister Reflection (SWP, Kil'jaeden) case 45892: // Sinister Reflection (SWP, Kil'jaeden)
case 45976: // Open Portal (SWP, M'uru) case 45976: // Open Portal (SWP, M'uru)
case 46372: // Ice Spear Target Picker (Slave Pens, Ahune) case 46372: // Ice Spear Target Picker (Slave Pens, Ahune)
@ -8000,15 +8001,15 @@ void Spell::GetSpellRangeAndRadius(SpellEffectEntry const* spellEffect, float& r
case 62797: // Storm Cloud (Ulduar, Hodir) case 62797: // Storm Cloud (Ulduar, Hodir)
case 63018: // Searing Light (Ulduar, XT-002) case 63018: // Searing Light (Ulduar, XT-002)
case 63024: // Gravity Bomb (Ulduar, XT-002) case 63024: // Gravity Bomb (Ulduar, XT-002)
case 63387: // Rapid Burst
case 63545: // Icicle (Ulduar, Hodir) case 63545: // Icicle (Ulduar, Hodir)
case 63795: // Psychosis (Ulduar, Yogg-Saron) case 63795: // Psychosis (Ulduar, Yogg-Saron)
case 63820: // Summon Scrap Bot Trigger (Ulduar, Mimiron) use for Scrap Bots, hits npc 33856 case 63820: // Summon Scrap Bot Trigger (Ulduar, Mimiron) use for Scrap Bots, hits npc 33856
case 64218: // Overcharge (VoA, Emalon) case 64218: // Overcharge (VoA, Emalon)
case 64234: // Gravity Bomb (h) (Ulduar, XT-002) case 64234: // Gravity Bomb (h) (Ulduar, XT-002)
case 64402: // Rocket Strike (Ulduar, Mimiron)
case 64425: // Summon Scrap Bot Trigger (Ulduar, Mimiron) use for Assault Bots, hits npc 33856 case 64425: // Summon Scrap Bot Trigger (Ulduar, Mimiron) use for Assault Bots, hits npc 33856
case 64531: // Rapid Burst (h)
case 64543: // Melt Ice (Ulduar, Hodir) case 64543: // Melt Ice (Ulduar, Hodir)
case 64623: // Frost Bomb (Ulduar, Mimiron)
case 65121: // Searing Light (h) (Ulduar, XT-002) case 65121: // Searing Light (h) (Ulduar, XT-002)
case 65301: // Psychosis (Ulduar, Yogg-Saron) case 65301: // Psychosis (Ulduar, Yogg-Saron)
case 65872: // Pursuing Spikes (ToCrusader, Anub'arak) case 65872: // Pursuing Spikes (ToCrusader, Anub'arak)

View file

@ -448,7 +448,7 @@ enum AuraType
SPELL_AURA_297 = 297, SPELL_AURA_297 = 297,
SPELL_AURA_298 = 298, SPELL_AURA_298 = 298,
SPELL_AURA_299 = 299, SPELL_AURA_299 = 299,
SPELL_AURA_300 = 300, SPELL_AURA_SHARE_DAMAGE_PCT = 300,
SPELL_AURA_HEAL_ABSORB = 301, SPELL_AURA_HEAL_ABSORB = 301,
SPELL_AURA_302 = 302, SPELL_AURA_302 = 302,
SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE = 303, SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE = 303,

View file

@ -1457,15 +1457,15 @@ void Aura::TriggerSpell()
// move loot to player inventory and despawn target // move loot to player inventory and despawn target
if (caster->GetTypeId() == TYPEID_PLAYER && if (caster->GetTypeId() == TYPEID_PLAYER &&
triggerTarget->GetTypeId() == TYPEID_UNIT && triggerTarget->GetTypeId() == TYPEID_UNIT &&
((Creature*)triggerTarget)->GetCreatureInfo()->type == CREATURE_TYPE_GAS_CLOUD) ((Creature*)triggerTarget)->GetCreatureInfo()->CreatureType == CREATURE_TYPE_GAS_CLOUD)
{ {
Player* player = (Player*)caster; Player* player = (Player*)caster;
Creature* creature = (Creature*)triggerTarget; Creature* creature = (Creature*)triggerTarget;
// missing lootid has been reported on startup - just return // missing Lootid has been reported on startup - just return
if (!creature->GetCreatureInfo()->SkinLootId) if (!creature->GetCreatureInfo()->SkinningLootId)
return; return;
player->AutoStoreLoot(creature, creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, true); player->AutoStoreLoot(creature, creature->GetCreatureInfo()->SkinningLootId, LootTemplates_Skinning, true);
creature->ForcedDespawn(); creature->ForcedDespawn();
} }
@ -2379,8 +2379,13 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
Spell::SelectMountByAreaAndSkill(target, GetSpellProto(), 0, 0, 54726, 54727, 0); Spell::SelectMountByAreaAndSkill(target, GetSpellProto(), 0, 0, 54726, 54727, 0);
return; return;
case 58600: // Restricted Flight Area case 58600: // Restricted Flight Area
target->MonsterWhisper(LANG_NO_FLY_ZONE, target, true); {
if (!target || target->GetTypeId() != TYPEID_PLAYER)
return; return;
const char* text = sObjectMgr.GetMangosString(LANG_NO_FLY_ZONE, ((Player*)target)->GetSession()->GetSessionDbLocaleIndex());
target->MonsterWhisper(text, target, true);
return;
}
case 61187: // Twilight Shift (single target) case 61187: // Twilight Shift (single target)
case 61190: // Twilight Shift (many targets) case 61190: // Twilight Shift (many targets)
target->RemoveAurasDueToSpell(57620); target->RemoveAurasDueToSpell(57620);
@ -2936,18 +2941,18 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
return; return;
} }
case 64398: // Summon Scrap Bot (Ulduar, Mimiron) - for Scrap Bots case 62483: // Stonebark's Essence Channel
case 64426: // Summon Scrap Bot (Ulduar, Mimiron) - for Assault Bots case 62484: // Ironbranch's Essence Channel
case 64621: // Summon Fire Bot (Ulduar, Mimiron) case 62485: // Brightleaf's Essence Channel
case 65587: // Brightleaf's Essence Channel (h)
case 65588: // Ironbranch's Essence Channel (h)
case 65589: // Stonebark's Essence Channel (h)
{ {
uint32 triggerSpell = 0; if (Unit* caster = GetCaster())
switch (GetId())
{ {
case 64398: triggerSpell = 63819; break; if (m_removeMode == AURA_REMOVE_BY_EXPIRE)
case 64426: triggerSpell = 64427; break; caster->CastSpell(caster, 62467, true);
case 64621: triggerSpell = 64622; break;
} }
target->CastSpell(target, triggerSpell, false);
return; return;
} }
case 68839: // Corrupt Soul case 68839: // Corrupt Soul
@ -4487,15 +4492,15 @@ void Aura::HandleModCharm(bool apply, bool Real)
if (caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK) if (caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK)
{ {
CreatureInfo const* cinfo = ((Creature*)target)->GetCreatureInfo(); CreatureInfo const* cinfo = ((Creature*)target)->GetCreatureInfo();
if (cinfo && cinfo->type == CREATURE_TYPE_DEMON) if (cinfo && cinfo->CreatureType == CREATURE_TYPE_DEMON)
{ {
// creature with pet number expected have class set // creature with pet number expected have class set
if (target->GetByteValue(UNIT_FIELD_BYTES_0, 1) == 0) if (target->GetByteValue(UNIT_FIELD_BYTES_0, 1) == 0)
{ {
if (cinfo->unit_class == 0) if (cinfo->UnitClass == 0)
sLog.outErrorDb("Creature (Entry: %u) have unit_class = 0 but used in charmed spell, that will be result client crash.", cinfo->Entry); sLog.outErrorDb("Creature (Entry: %u) have UnitClass = 0 but used in charmed spell, that will be result client crash.", cinfo->Entry);
else else
sLog.outError("Creature (Entry: %u) have unit_class = %u but at charming have class 0!!! that will be result client crash.", cinfo->Entry, cinfo->unit_class); sLog.outError("Creature (Entry: %u) have UnitClass = %u but at charming have class 0!!! that will be result client crash.", cinfo->Entry, cinfo->UnitClass);
target->SetByteValue(UNIT_FIELD_BYTES_0, 1, CLASS_MAGE); target->SetByteValue(UNIT_FIELD_BYTES_0, 1, CLASS_MAGE);
} }
@ -4533,10 +4538,10 @@ void Aura::HandleModCharm(bool apply, bool Real)
target->setFaction(cinfo->FactionAlliance); target->setFaction(cinfo->FactionAlliance);
// restore UNIT_FIELD_BYTES_0 // restore UNIT_FIELD_BYTES_0
if (cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->type == CREATURE_TYPE_DEMON) if (cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->CreatureType == CREATURE_TYPE_DEMON)
{ {
// DB must have proper class set in field at loading, not req. restore, including workaround case at apply // DB must have proper class set in field at loading, not req. restore, including workaround case at apply
// m_target->SetByteValue(UNIT_FIELD_BYTES_0, 1, cinfo->unit_class); // m_target->SetByteValue(UNIT_FIELD_BYTES_0, 1, cinfo->UnitClass);
if (target->GetCharmInfo()) if (target->GetCharmInfo())
{ target->GetCharmInfo()->SetPetNumber(0, true); } { target->GetCharmInfo()->SetPetNumber(0, true); }
@ -4947,13 +4952,8 @@ void Aura::HandleAuraModRoot(bool apply, bool Real)
if (GetSpellSchoolMask(GetSpellProto()) & SPELL_SCHOOL_MASK_FROST) if (GetSpellSchoolMask(GetSpellProto()) & SPELL_SCHOOL_MASK_FROST)
{ target->ModifyAuraState(AURA_STATE_FROZEN, apply); } { target->ModifyAuraState(AURA_STATE_FROZEN, apply); }
target->addUnitState(UNIT_STAT_ROOT);
target->SetTargetGuid(ObjectGuid()); target->SetTargetGuid(ObjectGuid());
// Save last orientation
if (target->getVictim())
target->SetOrientation(target->GetAngle(target->getVictim()));
if (target->GetTypeId() == TYPEID_PLAYER) if (target->GetTypeId() == TYPEID_PLAYER)
{ {
target->SetRoot(true); target->SetRoot(true);
@ -4991,20 +4991,16 @@ void Aura::HandleAuraModRoot(bool apply, bool Real)
// Real remove called after current aura remove from lists, check if other similar auras active // Real remove called after current aura remove from lists, check if other similar auras active
if (target->HasAuraType(SPELL_AURA_MOD_ROOT)) if (target->HasAuraType(SPELL_AURA_MOD_ROOT))
{ return; } {
return;
}
target->clearUnitState(UNIT_STAT_ROOT); target->clearUnitState(UNIT_STAT_ROOT);
if (!target->hasUnitState(UNIT_STAT_STUNNED)) // prevent allow move if have also stun effect if (!target->hasUnitState(UNIT_STAT_STUNNED) && (target->GetTypeId() == TYPEID_PLAYER)) // prevent allow move if have also stun effect
{
if (target->getVictim() && target->IsAlive())
target->SetTargetGuid(target->getVictim()->GetObjectGuid());
if (target->GetTypeId() == TYPEID_PLAYER)
target->SetRoot(false); target->SetRoot(false);
} }
} }
}
void Aura::HandleAuraModSilence(bool apply, bool Real) void Aura::HandleAuraModSilence(bool apply, bool Real)
{ {
@ -7027,7 +7023,7 @@ void Aura::HandleAuraEmpathy(bool apply, bool /*Real*/)
return; return;
CreatureInfo const* ci = ObjectMgr::GetCreatureTemplate(GetTarget()->GetEntry()); CreatureInfo const* ci = ObjectMgr::GetCreatureTemplate(GetTarget()->GetEntry());
if (ci && ci->type == CREATURE_TYPE_BEAST) if (ci && ci->CreatureType == CREATURE_TYPE_BEAST)
GetTarget()->ApplyModUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO, apply); GetTarget()->ApplyModUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO, apply);
} }
@ -8346,6 +8342,14 @@ void Aura::PeriodicDummyTick()
target->CastSpell(target, 63536, true, NULL, this); target->CastSpell(target, 63536, true, NULL, this);
return; return;
} }
case 63382: // Rapid Burst
{
if (GetAuraTicks() % 2)
target->CastSpell(target, target->GetMap()->IsRegularDifficulty() ? 64019 : 64532, true);
else
target->CastSpell(target, target->GetMap()->IsRegularDifficulty() ? 63387 : 64531, true);
return;
}
case 64217: // Overcharged case 64217: // Overcharged
{ {
if (GetHolder()->GetStackAmount() >= 10) if (GetHolder()->GetStackAmount() >= 10)
@ -8826,7 +8830,7 @@ void Aura::HandleAuraMirrorImage(bool apply, bool Real)
const CreatureModelInfo* minfo = sObjectMgr.GetCreatureModelInfo(pCreature->GetNativeDisplayId()); const CreatureModelInfo* minfo = sObjectMgr.GetCreatureModelInfo(pCreature->GetNativeDisplayId());
pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 0, 0); pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 0, 0);
pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 1, cinfo->unit_class); pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 1, cinfo->UnitClass);
pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender); pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender);
pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 3, 0); pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 3, 0);

View file

@ -1542,6 +1542,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
unitTarget->CastSpell(unitTarget, spell_id, true); unitTarget->CastSpell(unitTarget, spell_id, true);
return; return;
} }
case 41283: // Abyssal Toss
{
if (!unitTarget)
return;
m_caster->SummonCreature(23416, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000);
return;
}
case 41333: // Empyreal Equivalency case 41333: // Empyreal Equivalency
{ {
if (!unitTarget) if (!unitTarget)
@ -2738,6 +2746,31 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
unitTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); unitTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE);
return; return;
} }
case 62217: // Unstable Energy
case 62922: // Unstable Energy (h)
{
if (!unitTarget)
return;
unitTarget->RemoveAurasDueToSpell(effect->CalculateSimpleValue());
return;
}
case 62262: // Brightleaf Flux
{
if (!unitTarget)
return;
if (unitTarget->HasAura(62239))
unitTarget->RemoveAurasDueToSpell(62239);
else
{
uint32 stackAmount = urand(1, GetSpellStore()->LookupEntry(62239)->GetStackAmount());
for (uint8 i = 0; i < stackAmount; ++i)
unitTarget->CastSpell(unitTarget, 62239, true);
}
return;
}
case 62278: // Lightning Orb Charger case 62278: // Lightning Orb Charger
{ {
if (!unitTarget) if (!unitTarget)
@ -2747,6 +2780,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
unitTarget->CastSpell(unitTarget, 62279, true); unitTarget->CastSpell(unitTarget, 62279, true);
return; return;
} }
case 62652: // Tidal Wave
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, m_caster->GetMap()->IsRegularDifficulty() ? 62653 : 62935, true);
return;
}
case 62797: // Storm Cloud case 62797: // Storm Cloud
{ {
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
@ -2764,6 +2805,15 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true); m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return; return;
} }
case 63027: // Proximity Mines
{
if (!unitTarget)
return;
for (uint8 i = 0; i < 15; ++i)
unitTarget->CastSpell(unitTarget, 65347, true);
return;
}
case 63499: // Dispel Magic case 63499: // Dispel Magic
{ {
if (!unitTarget) if (!unitTarget)
@ -2779,6 +2829,22 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true); m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
} }
case 63667: // Napalm Shell
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, m_caster->GetMap()->IsRegularDifficulty() ? 63666 : 65026, true);
return;
}
case 63681: // Rocket Strike
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 63036, true);
return;
}
case 63820: // Summon Scrap Bot Trigger (Ulduar - Mimiron) for Scrap Bots case 63820: // Summon Scrap Bot Trigger (Ulduar - Mimiron) for Scrap Bots
case 64425: // Summon Scrap Bot Trigger (Ulduar - Mimiron) for Assault Bots case 64425: // Summon Scrap Bot Trigger (Ulduar - Mimiron) for Assault Bots
case 64620: // Summon Fire Bot Trigger (Ulduar - Mimiron) for Fire Bots case 64620: // Summon Fire Bot Trigger (Ulduar - Mimiron) for Fire Bots
@ -2801,6 +2867,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
m_caster->SetFacingTo(frand(0, M_PI_F * 2)); m_caster->SetFacingTo(frand(0, M_PI_F * 2));
return; return;
} }
case 64402: // Rocket Strike
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 63681, true);
return;
}
case 64489: // Feral Rush case 64489: // Feral Rush
{ {
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
@ -2818,6 +2892,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
m_caster->CastSpell(m_caster, 64540, true); m_caster->CastSpell(m_caster, 64540, true);
return; return;
} }
case 64623: // Frost Bomb
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 64627, true);
return;
}
case 64673: // Feral Rush (h) case 64673: // Feral Rush (h)
{ {
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
@ -2826,6 +2908,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
m_caster->CastSpell(unitTarget, 64674, true); m_caster->CastSpell(unitTarget, 64674, true);
return; return;
} }
case 64841: // Rapid Burst
{
if (!unitTarget)
return;
unitTarget->CastSpell(m_caster, 63382, false);
return;
}
case 64981: // Summon Random Vanquished Tentacle case 64981: // Summon Random Vanquished Tentacle
{ {
uint32 spell_id = 0; uint32 spell_id = 0;
@ -2840,6 +2930,16 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
m_caster->CastSpell(m_caster, spell_id, true); m_caster->CastSpell(m_caster, spell_id, true);
return; return;
} }
case 65346: // Proximity Mine
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(m_caster, m_caster->GetMap()->IsRegularDifficulty() ? 66351 : 63009, true);
m_caster->RemoveAurasDueToSpell(65345);
m_caster->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
return;
}
case 66390: // Read Last Rites case 66390: // Read Last Rites
{ {
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->GetTypeId() != TYPEID_PLAYER) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->GetTypeId() != TYPEID_PLAYER)
@ -5279,7 +5379,7 @@ void Spell::EffectSummonType(SpellEffectEntry const* effect)
return; return;
// FIXME: not all totems and similar cases selected by this check... // FIXME: not all totems and similar cases selected by this check...
if (cInfo->type == CREATURE_TYPE_TOTEM) if (cInfo->CreatureType == CREATURE_TYPE_TOTEM)
summonResult = DoSummonTotem(effect); summonResult = DoSummonTotem(effect);
else else
summonResult = DoSummonGuardian(summonPositions, summon_prop, effect, level); summonResult = DoSummonGuardian(summonPositions, summon_prop, effect, level);
@ -5468,7 +5568,7 @@ bool Spell::DoSummonCritter(CreatureSummonPositions& list, SummonPropertiesEntry
critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter... critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
// critter->InitLevelupSpellsForLevel(); // none? // critter->InitLevelupSpellsForLevel(); // none?
critter->SelectLevel(critter->GetCreatureInfo()); // some summoned creaters have different from 1 DB data for level/hp critter->SelectLevel(critter->GetCreatureInfo()); // some summoned creaters have different from 1 DB data for level/hp
critter->SetUInt32Value(UNIT_NPC_FLAGS, critter->GetCreatureInfo()->npcflag); critter->SetUInt32Value(UNIT_NPC_FLAGS, critter->GetCreatureInfo()->NpcFlags);
// some mini-pets have quests // some mini-pets have quests
// set timer for unsummon // set timer for unsummon
if (m_duration > 0) if (m_duration > 0)
@ -5538,7 +5638,7 @@ bool Spell::DoSummonGuardian(CreatureSummonPositions& list, SummonPropertiesEntr
// spawnCreature->SetName(""); // generated by client // spawnCreature->SetName(""); // generated by client
spawnCreature->SetOwnerGuid(m_caster->GetObjectGuid()); spawnCreature->SetOwnerGuid(m_caster->GetObjectGuid());
spawnCreature->SetPowerType(POWER_MANA); spawnCreature->SetPowerType(POWER_MANA);
spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, spawnCreature->GetCreatureInfo()->npcflag); spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, spawnCreature->GetCreatureInfo()->NpcFlags);
spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0); spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
spawnCreature->SetCreatorGuid(m_caster->GetObjectGuid()); spawnCreature->SetCreatorGuid(m_caster->GetObjectGuid());
@ -7597,6 +7697,23 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
unitTarget->CastSpell(unitTarget, triggeredSpell[urand(0, 3)], true); unitTarget->CastSpell(unitTarget, triggeredSpell[urand(0, 3)], true);
return; return;
} }
case 44323: // Hawk Hunting
case 44407: // Hawk Hunting
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// check target entry specific to each spell
if (m_spellInfo->Id == 44323 && unitTarget->GetEntry() != 24746)
return;
if (m_spellInfo->Id == 44407 && unitTarget->GetEntry() != 24747)
return;
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
// despawn delay depends on the distance between caster and target
((Creature*)unitTarget)->ForcedDespawn(100 * unitTarget->GetDistance2d(m_caster));
return;
}
case 44364: // Rock Falcon Primer case 44364: // Rock Falcon Primer
{ {
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
@ -7771,6 +7888,14 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
unitTarget->CastSpell(unitTarget, 45259, true); unitTarget->CastSpell(unitTarget, 45259, true);
return; return;
} }
case 45625: // Arcane Chains: Character Force Cast
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 45668: // Ultra-Advanced Proto-Typical Shortening Blaster case 45668: // Ultra-Advanced Proto-Typical Shortening Blaster
{ {
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
@ -7855,7 +7980,7 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
} }
else else
{ {
m_caster->SetUInt32Value(UNIT_NPC_FLAGS, cTemplate->npcflag); m_caster->SetUInt32Value(UNIT_NPC_FLAGS, cTemplate->NpcFlags);
((Creature*)m_caster)->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 0); ((Creature*)m_caster)->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 0);
((Creature*)m_caster)->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, 0); ((Creature*)m_caster)->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, 0);
@ -8643,6 +8768,28 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
unitTarget->CastSpell(m_caster, 64909, true); unitTarget->CastSpell(m_caster, 64909, true);
return; return;
} }
case 62282: // Iron Roots
case 62440: // Strengthened Iron Roots
case 63598: // Iron Roots (h)
case 63601: // Strengthened Iron Roots (h)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || !((Creature*)unitTarget)->IsTemporarySummon())
return;
uint32 ownerAura = 0;
switch (m_spellInfo->Id)
{
case 62282: ownerAura = 62283; break;
case 62440: ownerAura = 62438; break;
case 63598: ownerAura = 62930; break;
case 63601: ownerAura = 62861; break;
};
if (Unit* summoner = unitTarget->GetMap()->GetUnit(((TemporarySummon*)unitTarget)->GetSummonerGuid()))
summoner->RemoveAurasDueToSpell(ownerAura);
return;
}
case 62381: // Chill case 62381: // Chill
{ {
if (!unitTarget) if (!unitTarget)
@ -8685,18 +8832,6 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
unitTarget->RemoveAuraHolderFromStack(spellId, numStacks); unitTarget->RemoveAuraHolderFromStack(spellId, numStacks);
return; return;
} }
case 62678: // Summon Allies of Nature
{
const uint32 randSpells[] =
{
62685, // Summon Wave - 1 Mob
62686, // Summon Wave - 3 Mob
62688, // Summon Wave - 10 Mob
};
m_caster->CastSpell(m_caster, randSpells[urand(0, countof(randSpells) - 1)], true);
return;
}
case 62688: // Summon Wave - 10 Mob case 62688: // Summon Wave - 10 Mob
{ {
uint32 spellId = effect->CalculateSimpleValue(); uint32 spellId = effect->CalculateSimpleValue();

View file

@ -1214,6 +1214,13 @@ SpellAuraProcResult Unit::HandleDummyAuraProc(Unit* pVictim, uint32 damage, Aura
basepoints[0] = damage * 15 / 100; basepoints[0] = damage * 15 / 100;
break; break;
} }
// Fingers of Frost
case 74396:
{
// Remove only single aura from stack and remove holder if its last stack
RemoveAuraHolderFromStack(74396);
return SPELL_AURA_PROC_OK;
}
} }
break; break;
} }
@ -3111,6 +3118,12 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
(((Creature*)pVictim)->GetCreatureInfo()->MechanicImmuneMask & (1 << (MECHANIC_STUN - 1))) == 0) (((Creature*)pVictim)->GetCreatureInfo()->MechanicImmuneMask & (1 << (MECHANIC_STUN - 1))) == 0)
return SPELL_AURA_PROC_FAILED; return SPELL_AURA_PROC_FAILED;
} }
else if (auraSpellInfo->SpellIconID == 2947) // Fingers of Frost
{
// proc chance for spells in basepoints
if (!roll_chance_i(triggerAmount))
return SPELL_AURA_PROC_FAILED;
}
break; break;
} }
case SPELLFAMILY_WARRIOR: case SPELLFAMILY_WARRIOR:

View file

@ -779,6 +779,7 @@ void World::LoadConfigSettings(bool reload)
setConfigMinMax(CONFIG_FLOAT_GHOST_RUN_SPEED_BG, "Death.Ghost.RunSpeed.Battleground", 1.0f, 0.1f, 10.0f); setConfigMinMax(CONFIG_FLOAT_GHOST_RUN_SPEED_BG, "Death.Ghost.RunSpeed.Battleground", 1.0f, 0.1f, 10.0f);
setConfig(CONFIG_FLOAT_THREAT_RADIUS, "ThreatRadius", 100.0f); setConfig(CONFIG_FLOAT_THREAT_RADIUS, "ThreatRadius", 100.0f);
setConfigMin(CONFIG_UINT32_CREATURE_RESPAWN_AGGRO_DELAY, "CreatureRespawnAggroDelay", 5000, 0);
// always use declined names in the russian client // always use declined names in the russian client
if (getConfig(CONFIG_UINT32_REALM_ZONE) == REALM_ZONE_RUSSIAN) if (getConfig(CONFIG_UINT32_REALM_ZONE) == REALM_ZONE_RUSSIAN)
@ -812,7 +813,7 @@ void World::LoadConfigSettings(bool reload)
setConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET, "Network.KickOnBadPacket", false); setConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET, "Network.KickOnBadPacket", false);
setConfig(CONFIG_BOOL_PLAYER_COMMANDS, "PlayerCommands", false); setConfig(CONFIG_BOOL_PLAYER_COMMANDS, "PlayerCommands", true);
if (int clientCacheId = sConfig.GetIntDefault("ClientCacheVersion", 0)) if (int clientCacheId = sConfig.GetIntDefault("ClientCacheVersion", 0))
{ {
@ -1782,19 +1783,7 @@ namespace MaNGOS
while (char* line = lineFromMessage(pos)) while (char* line = lineFromMessage(pos))
{ {
WorldPacket* data = new WorldPacket(); WorldPacket* data = new WorldPacket();
ChatHandler::BuildChatPacket(*data, CHAT_MSG_SYSTEM, line);
uint32 lineLength = (line ? strlen(line) : 0) + 1;
data->Initialize(SMSG_MESSAGECHAT, 100);// guess size
*data << uint8(CHAT_MSG_SYSTEM);
*data << uint32(LANG_UNIVERSAL);
*data << uint64(0);
*data << uint32(0); // can be chat msg group or something
*data << uint64(0);
*data << uint32(lineLength);
*data << line;
*data << uint8(0);
data_list.push_back(data); data_list.push_back(data);
} }
} }

View file

@ -217,6 +217,7 @@ enum eConfigUInt32Values
CONFIG_UINT32_GUID_RESERVE_SIZE_CREATURE, CONFIG_UINT32_GUID_RESERVE_SIZE_CREATURE,
CONFIG_UINT32_GUID_RESERVE_SIZE_GAMEOBJECT, CONFIG_UINT32_GUID_RESERVE_SIZE_GAMEOBJECT,
CONFIG_UINT32_MIN_LEVEL_FOR_RAID, CONFIG_UINT32_MIN_LEVEL_FOR_RAID,
CONFIG_UINT32_CREATURE_RESPAWN_AGGRO_DELAY,
CONFIG_UINT32_RANDOM_BG_RESET_HOUR, CONFIG_UINT32_RANDOM_BG_RESET_HOUR,
// Warden // Warden
CONFIG_UINT32_WARDEN_CLIENT_RESPONSE_DELAY, CONFIG_UINT32_WARDEN_CLIENT_RESPONSE_DELAY,

View file

@ -785,6 +785,11 @@ SD2ErrorLogFile = "scriptdev2-errors.log"
# You can bypass this setting by typing "/script SetAllowLowLevelRaid(true/false)" command in chat # You can bypass this setting by typing "/script SetAllowLowLevelRaid(true/false)" command in chat
# Default: 10 # Default: 10
# #
# PlayerCommands
# Should player chat be parsed for GM commands.
# Default: 1 (parse commands)
# 0 (ignore commands)
#
################################################################################ ################################################################################
GameType = 1 GameType = 1
@ -856,6 +861,7 @@ WaitAtStartupError = 10
PlayerCommands = 0 PlayerCommands = 0
Motd = "Welcome to Mangos Three." Motd = "Welcome to Mangos Three."
Raid.MinLevel = 10 Raid.MinLevel = 10
PlayerCommands = 1
################################################################################ ################################################################################
# PLAYER INTERACTION # PLAYER INTERACTION
@ -1008,6 +1014,7 @@ TalentsInspecting = 1
ThreatRadius = 100 ThreatRadius = 100
Rate.Creature.Aggro = 1 Rate.Creature.Aggro = 1
CreatureRespawnAggroDelay = 5000
CreatureFamilyFleeAssistanceRadius = 30 CreatureFamilyFleeAssistanceRadius = 30
CreatureFamilyAssistanceRadius = 10 CreatureFamilyAssistanceRadius = 10
CreatureFamilyAssistanceDelay = 1500 CreatureFamilyAssistanceDelay = 1500

View file

@ -144,7 +144,7 @@ bool npc_escortAI::AssistPlayerInCombat(Unit* pWho)
return false; return false;
} }
// unit state prevents (similar check is done in CanInitiateAttack which also include checking unit_flags. We skip those here) // unit state prevents (similar check is done in CanInitiateAttack which also include checking UnitFlags. We skip those here)
if (m_creature->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_DIED)) if (m_creature->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_DIED))
{ {
return false; return false;
@ -629,7 +629,7 @@ void npc_escortAI::Start(bool bRun, const Player* pPlayer, const Quest* pQuest,
debug_log("SD3: EscortAI start with WAYPOINT_MOTION_TYPE, changed to MoveIdle."); debug_log("SD3: EscortAI start with WAYPOINT_MOTION_TYPE, changed to MoveIdle.");
} }
// disable npcflags // disable NpcFlagss
m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
debug_log("SD3: EscortAI started with " SIZEFMTD " waypoints. Run = %d, PlayerGuid = %s", WaypointList.size(), m_bIsRunning, m_playerGuid.GetString().c_str()); debug_log("SD3: EscortAI started with " SIZEFMTD " waypoints. Run = %d, PlayerGuid = %s", WaypointList.size(), m_bIsRunning, m_playerGuid.GetString().c_str());

View file

@ -82,7 +82,7 @@ bool FollowerAI::AssistPlayerInCombat(Unit* pWho)
return false; return false;
} }
// unit state prevents (similar check is done in CanInitiateAttack which also include checking unit_flags. We skip those here) // unit state prevents (similar check is done in CanInitiateAttack which also include checking UnitFlags. We skip those here)
if (m_creature->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_DIED)) if (m_creature->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_DIED))
{ {
return false; return false;

View file

@ -92,7 +92,7 @@ struct npc_kitten : public CreatureScript
void MoveInLineOfSight(Unit* pWho) override void MoveInLineOfSight(Unit* pWho) override
{ {
// should not have npcflag by default, so set when expected // should not have NpcFlags by default, so set when expected
if (!m_creature->getVictim() && !m_creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP) && HasFollowState(STATE_FOLLOW_INPROGRESS) && pWho->GetEntry() == NPC_WINNA) if (!m_creature->getVictim() && !m_creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP) && HasFollowState(STATE_FOLLOW_INPROGRESS) && pWho->GetEntry() == NPC_WINNA)
{ {
if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE)) if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE))

View file

@ -86,7 +86,7 @@ struct boss_moam : public CreatureScript
m_creature->SetMaxPower(POWER_MANA, m_creature->GetCreatureInfo()->MaxLevelMana); m_creature->SetMaxPower(POWER_MANA, m_creature->GetCreatureInfo()->MaxLevelMana);
#endif #endif
#if defined (CATA) #if defined (CATA)
m_creature->SetMaxPower(POWER_MANA, m_creature->GetCreatureInfo()->maxmana);// TODO MaxLevelHealth); m_creature->SetMaxPower(POWER_MANA, m_creature->GetCreatureInfo()->MaxLevelMana);// TODO MaxLevelHealth);
#endif #endif
} }

View file

@ -102,7 +102,7 @@ struct mob_lump : public CreatureScript
m_creature->DeleteThreatList(); m_creature->DeleteThreatList();
m_creature->CombatStop(true); m_creature->CombatStop(true);
// should get unit_flags UNIT_FLAG_OOC_NOT_ATTACKABLE | UNIT_FLAG_PASSIVE at faction change, but unclear why/for what reason, skipped (no flags expected as default) // should get UnitFlags UNIT_FLAG_OOC_NOT_ATTACKABLE | UNIT_FLAG_PASSIVE at faction change, but unclear why/for what reason, skipped (no flags expected as default)
m_creature->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_REACH_HOME); m_creature->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_REACH_HOME);
m_creature->SetStandState(UNIT_STAND_STATE_SIT); m_creature->SetStandState(UNIT_STAND_STATE_SIT);

View file

@ -1213,9 +1213,9 @@ struct npc_guardian : public CreatureScript
# npc_innkeeper # npc_innkeeper
#########*/ #########*/
// Script applied to all innkeepers by npcflag. // Script applied to all innkeepers by NpcFlags.
// Are there any known innkeepers that does not hape the options in the below? // Are there any known innkeepers that does not hape the options in the below?
// (remember gossipHello is not called unless npcflag|1 is present) // (remember gossipHello is not called unless NpcFlags|1 is present)
enum enum
{ {

View file

@ -41,18 +41,6 @@ BarGoLink::BarGoLink(int row_count)
init(row_count); init(row_count);
} }
BarGoLink::BarGoLink(uint32 row_count)
{
MANGOS_ASSERT(row_count < (uint32)ACE_INT32_MAX);
init((int)row_count);
}
BarGoLink::BarGoLink(uint64 row_count)
{
MANGOS_ASSERT(row_count < (uint64)ACE_INT32_MAX);
init((int)row_count);
}
BarGoLink::~BarGoLink() BarGoLink::~BarGoLink()
{ {
if (!m_showOutput) if (!m_showOutput)

View file

@ -40,8 +40,6 @@ class BarGoLink
* @param row_count * @param row_count
*/ */
explicit BarGoLink(int row_count); explicit BarGoLink(int row_count);
explicit BarGoLink(uint32 row_count); // row_count < ACE_INT32_MAX
explicit BarGoLink(uint64 row_count); // row_count < ACE_INT64_MAX
/** /**
* @brief * @brief
* *