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);
ObjectGuid sourceGuid = i_source ? i_source->GetObjectGuid() : ObjectGuid();
std::string sourceName = i_source ? i_source->GetName() : "";
if (i_args)
{
// we need copy va_list before use or original va_list will corrupted
@ -63,26 +66,12 @@ namespace MaNGOS
vsnprintf(str, 2048, text, 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
do_helper(data, text);
ChatHandler::BuildChatPacket(data, i_msgtype, text, LANG_UNIVERSAL, CHAT_TAG_NONE, sourceGuid, sourceName.c_str(), sourceGuid, sourceName.c_str());
}
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;
int32 i_textId;
Player const* i_source;
@ -91,8 +80,8 @@ namespace MaNGOS
class BattleGroundYellBuilder
{
public:
BattleGroundYellBuilder(uint32 language, int32 textId, Creature const* source, va_list* args = NULL)
public:
BattleGroundYellBuilder(Language language, int32 textId, Creature const* source, va_list* args = nullptr)
: i_language(language), i_textId(textId), i_source(source), i_args(args) {}
void operator()(WorldPacket& data, int32 loc_idx)
{
@ -108,28 +97,13 @@ namespace MaNGOS
vsnprintf(str, 2048, text, 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
do_helper(data, text);
ChatHandler::BuildChatPacket(data, CHAT_MSG_MONSTER_YELL, text, i_language, CHAT_TAG_NONE, i_source->GetObjectGuid(), i_source->GetName());
}
private:
void do_helper(WorldPacket& data, char const* text)
{
// 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;
Language i_language;
int32 i_textId;
Creature const* i_source;
va_list* i_args;
@ -150,19 +124,16 @@ namespace MaNGOS
char str [2048];
snprintf(str, 2048, text, arg1str, arg2str);
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(str) + 1);
data << str;
data << uint8(i_source ? i_source->GetChatTag() : uint8(CHAT_TAG_NONE));
ObjectGuid guid;
char const* pName = nullptr;
if (i_source)
{
guid = i_source->GetObjectGuid();
pName = i_source->GetName();
}
ChatHandler::BuildChatPacket(data, i_msgtype, str, LANG_UNIVERSAL, CHAT_TAG_NONE, ObjectGuid(), nullptr, guid, pName);
}
private:
ChatMsg i_msgtype;
int32 i_textId;
Player const* i_source;
@ -1589,7 +1560,7 @@ void BattleGround::SendYellToAll(int32 entry, uint32 language, ObjectGuid guid)
Creature* source = GetBgMap()->GetCreature(guid);
if (!source)
return;
MaNGOS::BattleGroundYellBuilder bg_builder(language, entry, source);
MaNGOS::BattleGroundYellBuilder bg_builder(Language(language), entry, source);
MaNGOS::LocalizedPacketDo<MaNGOS::BattleGroundYellBuilder> bg_do(bg_builder);
BroadcastWorker(bg_do);
}

View file

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

View file

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

View file

@ -1878,7 +1878,7 @@ bool ChatHandler::HandleNpcChangeLevelCommand(char* args)
return true;
}
// set npcflag of creature
// set NpcFlags of creature
bool ChatHandler::HandleNpcFlagCommand(char* args)
{
if (!*args)
@ -1897,7 +1897,7 @@ bool ChatHandler::HandleNpcFlagCommand(char* args)
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);

View file

@ -1137,6 +1137,14 @@ bool ChatHandler::HandleReloadMailLevelRewardCommand(char* /*args*/)
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)
{
if (!*args)
@ -2472,7 +2480,7 @@ bool ChatHandler::HandleLearnAllMyPetTalentsCommand(char* /*args*/)
return false;
}
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family);
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->Family);
if (!pet_family)
{
SendSysMessage(LANG_WRONG_PET_TYPE);
@ -4338,7 +4346,7 @@ bool ChatHandler::HandleNpcInfoCommand(char* /*args*/)
}
uint32 faction = target->getFaction();
uint32 npcflags = target->GetUInt32Value(UNIT_NPC_FLAGS);
uint32 NpcFlagss = target->GetUInt32Value(UNIT_NPC_FLAGS);
uint32 displayid = target->GetDisplayId();
uint32 nativeid = target->GetNativeDisplayId();
uint32 Entry = target->GetEntry();
@ -4358,25 +4366,25 @@ bool ChatHandler::HandleNpcInfoCommand(char* /*args*/)
break;
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,
displayid, nativeid);
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_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_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_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);
}
if ((npcflags & UNIT_NPC_FLAG_TRAINER))
if ((NpcFlagss & UNIT_NPC_FLAG_TRAINER))
{
SendSysMessage(LANG_NPCINFO_TRAINER);
}

View file

@ -313,7 +313,7 @@ bool ChatHandler::HandleDebugSendChatMsgCommand(char* args)
return false;
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);
return true;
}

View file

@ -46,13 +46,42 @@ RandomMovementGenerator<Creature>::RandomMovementGenerator(const Creature& creat
template<>
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 range = rand_norm_f() * i_radius;
float destX = i_x + range * cos(angle);
float destY = i_y + range * sin(angle);
float destZ = i_z + frand(-1, 1) * i_verticalZ;
float destX = i_x;
float destY = i_y;
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.addUnitState(UNIT_STAT_ROAMING_MOVE);
@ -67,6 +96,7 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
else
i_nextMoveTime.Reset(urand(500, 10000));
}
*/
template<>
void RandomMovementGenerator<Creature>::Initialize(Creature& creature)

View file

@ -27,6 +27,9 @@
#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>
class RandomMovementGenerator
: public MovementGeneratorMedium< T, RandomMovementGenerator<T> >

View file

@ -142,6 +142,7 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature)
if (behavior->textid[0])
{
int32 textId = behavior->textid[0];
// Not only one text is set
if (behavior->textid[1])
{
@ -153,10 +154,13 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature)
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
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,8 +846,24 @@ void WorldSession::BuildListAuctionItems(std::vector<AuctionEntry*> const& aucti
if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax)))
continue;
if (usable != 0x00 && _player->CanUseItem(item) != EQUIP_ERR_OK)
continue;
if (usable != 0x00)
{
if (_player->CanUseItem(item) != EQUIP_ERR_OK)
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;
sObjectMgr.GetItemLocaleStrings(proto->ItemId, loc_idx, &name);

View file

@ -165,7 +165,7 @@ Creature::Creature(CreatureSubtype subtype) : Unit(),
lootForPickPocketed(false), lootForBody(false), lootForSkin(false),
m_groupLootTimer(0), m_groupLootId(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_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(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);
// 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);
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))
return false;
m_regenHealth = GetCreatureInfo()->RegenHealth;
// creatures always have melee weapon ready if any
SetSheath(SHEATH_STATE_MELEE);
SelectLevel(GetCreatureInfo(), preserveHPAndPower ? GetHealthPercent() : 100.0f, 100.0f);
SelectLevel(GetCreatureInfo(), preserveHPAndPower ? GetHealthPercent() : 100.0f);
if (team == HORDE)
setFaction(GetCreatureInfo()->FactionHorde);
else
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(OFF_ATTACK, attackTimer - attackTimer / 4);
SetAttackTime(RANGED_ATTACK, GetCreatureInfo()->rangeattacktime);
SetAttackTime(RANGED_ATTACK, GetCreatureInfo()->RangedBaseAttackTime);
uint32 unitFlags = GetCreatureInfo()->unit_flags;
uint32 unitFlags2 = GetCreatureInfo()->unit_flags2;
uint32 unitFlags = GetCreatureInfo()->UnitFlags;
uint32 unitFlags2 = GetCreatureInfo()->UnitFlags2;
// we may need to append or remove additional flags
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
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_RESISTANCE_HOLY, BASE_VALUE, float(GetCreatureInfo()->resistance1));
SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(GetCreatureInfo()->resistance2));
SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(GetCreatureInfo()->resistance3));
SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(GetCreatureInfo()->resistance4));
SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(GetCreatureInfo()->resistance5));
SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(GetCreatureInfo()->resistance6));
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(GetCreatureInfo()->Armor));
SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(GetCreatureInfo()->ResistanceHoly));
SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(GetCreatureInfo()->ResistanceFire));
SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(GetCreatureInfo()->ResistanceNature));
SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(GetCreatureInfo()->ResistanceFrost));
SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(GetCreatureInfo()->ResistanceShadow));
SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(GetCreatureInfo()->ResistanceArcane));
SetCanModifyStats(true);
UpdateAllStats();
@ -518,6 +516,7 @@ void Creature::Update(uint32 update_diff, uint32 diff)
{
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Respawning...");
m_respawnTime = 0;
m_aggroDelay = sWorld.getConfig(CONFIG_UINT32_CREATURE_RESPAWN_AGGRO_DELAY);
lootForPickPocketed = false;
lootForBody = false;
lootForSkin = false;
@ -535,6 +534,7 @@ void Creature::Update(uint32 update_diff, uint32 diff)
CreatureInfo const* cinfo = GetCreatureInfo();
SelectLevel(cinfo);
UpdateAllStats(); // to be sure stats is correct regarding level of the creature
SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE);
if (m_IsDeadByDefault)
{
@ -584,6 +584,11 @@ void Creature::Update(uint32 update_diff, uint32 diff)
}
case ALIVE:
{
if (m_aggroDelay <= update_diff)
m_aggroDelay = 0;
else
m_aggroDelay -= update_diff;
if (m_IsDeadByDefault)
{
if (m_corpseDecayTimer <= update_diff)
@ -819,7 +824,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
return false;
// 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* 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:
if (pPlayer->getClass() != GetCreatureInfo()->trainer_class)
if (pPlayer->getClass() != GetCreatureInfo()->TrainerClass)
{
if (msg)
{
pPlayer->PlayerTalkClass->ClearMenus();
switch (GetCreatureInfo()->trainer_class)
switch (GetCreatureInfo()->TrainerClass)
{
case CLASS_DRUID: pPlayer->PlayerTalkClass->SendGossipMenu(4913, GetObjectGuid()); break;
case CLASS_HUNTER: pPlayer->PlayerTalkClass->SendGossipMenu(10090, GetObjectGuid()); break;
@ -869,7 +874,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
}
break;
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
if (FactionTemplateEntry const* faction_template = getFactionTemplateEntry())
@ -881,7 +886,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
if (msg)
{
pPlayer->PlayerTalkClass->ClearMenus();
switch (GetCreatureInfo()->trainer_class)
switch (GetCreatureInfo()->TrainerClass)
{
case RACE_DWARF: pPlayer->PlayerTalkClass->SendGossipMenu(5865, GetObjectGuid()); break;
case RACE_GNOME: pPlayer->PlayerTalkClass->SendGossipMenu(4881, GetObjectGuid()); break;
@ -899,7 +904,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
}
break;
case TRAINER_TYPE_TRADESKILLS:
if (GetCreatureInfo()->trainer_spell && !pPlayer->HasSpell(GetCreatureInfo()->trainer_spell))
if (GetCreatureInfo()->TrainerSpell && !pPlayer->HasSpell(GetCreatureInfo()->TrainerSpell))
{
if (msg)
{
@ -953,8 +958,8 @@ bool Creature::CanInteractWithBattleMaster(Player* pPlayer, bool msg) const
bool Creature::CanTrainAndResetTalentsOf(Player* pPlayer) const
{
return pPlayer->getLevel() >= 10
&& GetCreatureInfo()->trainer_type == TRAINER_TYPE_CLASS
&& pPlayer->getClass() == GetCreatureInfo()->trainer_class;
&& GetCreatureInfo()->TrainerType == TRAINER_TYPE_CLASS
&& pPlayer->getClass() == GetCreatureInfo()->TrainerType;
}
void Creature::PrepareBodyLootState()
@ -965,9 +970,9 @@ void Creature::PrepareBodyLootState()
if (!lootForBody)
{
// have normal loot
if (GetCreatureInfo()->maxgold > 0 || GetCreatureInfo()->lootid ||
if (GetCreatureInfo()->MaxLootGold > 0 || GetCreatureInfo()->LootId ||
// ... 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);
return;
@ -977,7 +982,7 @@ void Creature::PrepareBodyLootState()
lootForBody = true; // pass this loot mode
// if not have normal loot allow skinning if need
if (!lootForSkin && GetCreatureInfo()->SkinLootId)
if (!lootForSkin && GetCreatureInfo()->SkinningLootId)
{
RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
@ -1162,25 +1167,59 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
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
uint32 minlevel = std::min(cinfo->maxlevel, cinfo->minlevel);
uint32 maxlevel = std::max(cinfo->maxlevel, cinfo->minlevel);
uint32 const minlevel = cinfo->MinLevel;
uint32 const maxlevel = cinfo->MaxLevel;
uint32 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel);
SetLevel(level);
float rellevel = maxlevel == minlevel ? 0 : (float(level - minlevel)) / (maxlevel - minlevel);
//////////////////////////////////////////////////////////////////////////
// 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);
// health
uint32 minhealth = std::min(cinfo->MaxLevelHealth, cinfo->MinLevelHealth);
uint32 maxhealth = std::max(cinfo->MaxLevelHealth, cinfo->MinLevelHealth);
health = uint32(minhealth + uint32(rellevel * (maxhealth - minhealth)));
// mana
uint32 minmana = std::min(cinfo->MaxLevelMana, cinfo->MinLevelMana);
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
float healthmod = _GetHealthMod(rank);
uint32 minhealth = std::min(cinfo->maxhealth, cinfo->minhealth);
uint32 maxhealth = std::max(cinfo->maxhealth, cinfo->minhealth);
uint32 health = uint32(healthmod * (minhealth + uint32(rellevel * (maxhealth - minhealth))));
SetCreateHealth(health);
SetMaxHealth(health);
@ -1189,33 +1228,51 @@ void Creature::SelectLevel(const CreatureInfo* cinfo, float percentHealth, float
else
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_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
float damagemod = _GetDamageMod(rank);
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod);
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod);
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->MinMeleeDmg * damagemod);
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->MaxMeleeDmg * damagemod);
SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod);
SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod);
SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->MinMeleeDmg * damagemod);
SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, cinfo->MaxMeleeDmg * damagemod);
SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, cinfo->minrangedmg * damagemod);
SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, cinfo->maxrangedmg * damagemod);
SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, cinfo->MinRangedDmg * 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)
@ -1370,7 +1427,7 @@ bool Creature::LoadFromDB(uint32 guidlow, Map* map)
SetHealth(m_deathState == ALIVE ? curhealth : 0);
SetPower(POWER_MANA, data->curmana);
SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->dmgschool));
SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->DamageSchool));
// checked at creature_template loading
m_defaultMovementType = MovementGeneratorType(data->movementType);
@ -1561,7 +1618,7 @@ void Creature::SetDeathState(DeathState s)
if (GetTemporaryFactionFlags() & TEMPFACTION_RESTORE_RESPAWN)
ClearTemporaryFaction();
SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->dmgschool));
SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->DamageSchool));
// Dynamic flags may be adjusted by spells. Clear them
// 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
// 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);
SetWalk(true, true);
@ -1634,7 +1691,7 @@ bool Creature::IsImmuneToSpellEffect(SpellEntry const* spellInfo, SpellEffectInd
return true;
// 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
if (spellEffect->Effect == SPELL_EFFECT_APPLY_AURA)
@ -1775,7 +1832,7 @@ bool Creature::IsVisibleInGridForPlayer(Player* pl) const
if (pl->isGameMaster())
return true;
if (GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_INVISIBLE)
if (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_INVISIBLE)
return false;
// 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())
{
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));
}
}
@ -1888,6 +1949,12 @@ bool Creature::CanInitiateAttack()
if (isPassiveToHostile())
return false;
if (m_aggroDelay != 0)
return false;
if (!CanAttackByItself())
return false;
return true;
}
@ -2350,8 +2417,8 @@ VendorItemData const* Creature::GetVendorItems() const
VendorItemData const* Creature::GetVendorTemplateItems() const
{
uint32 vendorId = GetCreatureInfo()->vendorId;
return vendorId ? sObjectMgr.GetNpcVendorTemplateItemList(vendorId) : NULL;
uint32 VendorTemplateId = GetCreatureInfo()->VendorTemplateId;
return VendorTemplateId ? sObjectMgr.GetNpcVendorTemplateItemList(VendorTemplateId) : NULL;
}
uint32 Creature::GetVendorItemCurrentCount(VendorItem const* vItem)
@ -2428,8 +2495,8 @@ uint32 Creature::UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 us
TrainerSpellData const* Creature::GetTrainerTemplateSpells() const
{
uint32 trainerId = GetCreatureInfo()->trainerId;
return trainerId ? sObjectMgr.GetNpcTrainerTemplateSpells(trainerId) : NULL;
uint32 TrainerTemplateId = GetCreatureInfo()->TrainerTemplateId;
return TrainerTemplateId ? sObjectMgr.GetNpcTrainerTemplateSpells(TrainerTemplateId) : NULL;
}
TrainerSpellData const* Creature::GetTrainerSpells() const
@ -2469,11 +2536,11 @@ void Creature::ClearTemporaryFaction()
// Reset to original faction
setFaction(GetCreatureInfo()->FactionAlliance);
// 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);
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);
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);
m_temporaryFactionFlags = TEMPFACTION_NONE;

View file

@ -49,17 +49,23 @@ struct GameEventCreatureData;
enum CreatureFlagsExtra
{
CREATURE_FLAG_EXTRA_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_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry
CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry
CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block
CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks
CREATURE_FLAG_EXTRA_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_FLAG_EXTRA_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_FLAG_EXTRA_GUARD = 0x00000400, // creature is a guard
CREATURE_EXTRA_FLAG_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group
CREATURE_EXTRA_FLAG_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility)
CREATURE_EXTRA_FLAG_NO_PARRY = 0x00000004, // creature can't parry
CREATURE_EXTRA_FLAG_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry
CREATURE_EXTRA_FLAG_NO_BLOCK = 0x00000010, // creature can't block
CREATURE_EXTRA_FLAG_NO_CRUSH = 0x00000020, // creature can't do crush attacks
CREATURE_EXTRA_FLAG_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP
CREATURE_EXTRA_FLAG_INVISIBLE = 0x00000080, // creature is always invisible for player (mostly trigger creatures)
CREATURE_EXTRA_FLAG_NOT_TAUNTABLE = 0x00000100, // creature is immune to taunt auras and effect attack me
CREATURE_EXTRA_FLAG_AGGRO_ZONE = 0x00000200, // creature sets itself in combat with zone on aggro
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
@ -72,8 +78,124 @@ enum CreatureFlagsExtra
#define MAX_KILL_CREDIT 2
#define MAX_CREATURE_MODEL 4
// from `creature_template` table
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 DifficultyEntry[MAX_DIFFICULTY - 1];
@ -83,16 +205,16 @@ struct CreatureInfo
char* SubName;
char* IconName;
uint32 GossipMenuId;
uint32 minlevel;
uint32 maxlevel;
uint32 minhealth;
uint32 MinLevel;
uint32 MaxLevel;
uint32 MinLevelHealth;
uint32 maxhealth;
uint32 minmana;
uint32 MinLevelMana;
uint32 maxmana;
uint32 armor;
uint32 FactionAlliance;
uint32 FactionHorde;
uint32 npcflag;
uint32 NpcFlags;
float speed_walk;
float speed_run;
float Scale;
@ -102,25 +224,25 @@ struct CreatureInfo
uint32 dmgschool;
uint32 attackpower;
float dmg_multiplier;
uint32 baseattacktime;
uint32 rangeattacktime;
uint32 unit_class; // enum Classes. Note only 4 classes are known for creatures.
uint32 unit_flags; // enum UnitFlags mask values
uint32 unit_flags2; // enum UnitFlags2 mask values
uint32 MeleeAttackPower;
uint32 RangedAttackPower;
uint32 UnitClass; // enum Classes. Note only 4 classes are known for creatures.
uint32 UnitFlags; // enum UnitFlags mask values
uint32 UnitFlags2; // enum UnitFlags2 mask values
uint32 dynamicflags;
uint32 family; // enum CreatureFamily values (optional)
uint32 trainer_type;
uint32 TrainerType;
uint32 trainer_spell;
uint32 trainer_class;
uint32 TrainerClass;
uint32 trainer_race;
float minrangedmg;
float maxrangedmg;
uint32 rangedattackpower;
uint32 type; // enum CreatureType values
uint32 CreatureTypeFlags; // enum CreatureTypeFlags mask values
uint32 lootid;
uint32 Lootid;
uint32 pickpocketLootId;
uint32 SkinLootId;
uint32 SkinningLootId;
int32 resistance1;
int32 resistance2;
int32 resistance3;
@ -128,7 +250,7 @@ struct CreatureInfo
int32 resistance5;
int32 resistance6;
uint32 PetSpellDataId;
uint32 mingold;
uint32 MinLootGold;
uint32 maxgold;
char const* AIName;
uint32 MovementType;
@ -141,8 +263,8 @@ struct CreatureInfo
bool RegenHealth;
uint32 VehicleTemplateId;
uint32 EquipmentTemplateId;
uint32 trainerId;
uint32 vendorId;
uint32 TrainerTemplateId;
uint32 VendorTemplateId;
uint32 MechanicImmuneMask;
uint32 ExtraFlags;
@ -179,7 +301,7 @@ struct CreatureInfo
// if can tame exotic then can tame any temable
return exotic || !IsExotic();
}
};
}; */
struct CreatureTemplateSpells
{
@ -330,6 +452,12 @@ enum SelectFlags
SELECT_FLAG_NOT_IN_MELEE_RANGE = 0x080,
};
enum RegenStatsFlags
{
REGEN_FLAG_HEALTH = 0x001,
REGEN_FLAG_POWER = 0x002,
};
// Vendors
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 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);
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; }
uint32 GetCorpseDelay() const { return m_corpseDelay; }
bool IsRacialLeader() const { return GetCreatureInfo()->RacialLeader; }
bool IsCivilian() const { return GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_CIVILIAN; }
bool IsGuard() const { return GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_GUARD; }
bool IsCivilian() const { return GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_CIVILIAN; }
bool IsGuard() const { return GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_GUARD; }
bool CanWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; }
virtual 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 CanSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; }
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 CanInteractWithBattleMaster(Player* player, bool msg) const;
@ -745,7 +875,8 @@ class Creature : public Unit
bool HasInvolvedQuest(uint32 quest_id) const override;
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 uint32 GetPetAutoSpellOnPos(uint8 pos) const
{
@ -802,6 +933,7 @@ class Creature : public Unit
time_t m_respawnTime; // (secs) time of next respawn
uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning
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;
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;
case ACTION_T_COMBAT_MOVEMENT:
// 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;
SetCombatMovement(action.combat_movement.state != 0, true);
@ -966,63 +966,38 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
m_throwAIEventMask = action.setThrowMask.eventTypeMask;
break;
}
case ACTION_T_SUMMON_UNIQUE:
case ACTION_T_SET_STAND_STATE:
{
Creature* pCreature = NULL;
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;
}
if (pSpawn)
{
return;
}
m_creature->SetStandState(action.setStandState.standState);
break;
}
case ACTION_T_EMOTE_TARGET:
case ACTION_T_CHANGE_MOVEMENT:
{
Unit* pCreature = m_creature->GetMap()->GetCreature(ObjectGuid(HIGHGUID_UNIT, action.emoteTarget.targetGuid));
if (!pCreature)
switch (action.changeMovement.movementType)
{
sLog.outErrorEventAI("Event %d. Cannot find creature by guid %d", EventId, action.emoteTarget.targetGuid);
return;
case IDLE_MOTION_TYPE:
m_creature->GetMotionMaster()->MoveIdle();
break;
case RANDOM_MOTION_TYPE:
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_creature->SetFacingToObject(pCreature);
m_creature->HandleEmote(action.emoteTarget.emoteId);
m_DynamicMovement = action.dynamicMovement.state;
SetCombatMovement(!m_DynamicMovement, true);
break;
}
default:
sLog.outError("CreatureEventAi::ProcessAction(): action(%u) not implemented", static_cast<uint32>(action.type));
break;
}
}

View file

@ -121,10 +121,12 @@ enum EventAI_ActionType
ACTION_T_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue, format(0-flat,1-percent from max health)
ACTION_T_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to unmount)
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_SUMMON_UNIQUE = 47, // CreatureId, Target, SpawnId
ACTION_T_EMOTE_TARGET = 48, // EmoteId, TargetGuid
ACTION_T_SET_STAND_STATE = 47, // StandState, unused, unused
ACTION_T_CHANGE_MOVEMENT = 48, // MovementType, WanderDistance, unused
ACTION_T_DYNAMIC_MOVEMENT = 49, // EnableDynamicMovement (1 = on; 0 = off)
ACTION_T_END,
};
@ -173,7 +175,7 @@ enum SpawnedEventMode
struct CreatureEventAI_Action
{
EventAI_ActionType type: 16;
EventAI_ActionType type : 16;
union
{
// ACTION_T_TEXT = 1
@ -384,7 +386,6 @@ struct CreatureEventAI_Action
uint32 creatureId; // set one from fields (or 0 for both to dismount)
uint32 modelId;
} mount;
// ACTION_T_CHANCED_TEXT = 44
struct
{
@ -405,19 +406,27 @@ struct CreatureEventAI_Action
uint32 unused1;
uint32 unused2;
} setThrowMask;
// ACTION_T_SUMMON_UNIQUE = 47
// ACTION_T_SET_STAND_STATE = 47
struct
{
uint32 creatureId;
uint32 target;
uint32 spawnId;
} summon_unique;
// ACTION_T_EMOTE_TARGET = 48
uint32 standState;
uint32 unused1;
uint32 unused2;
} setStandState;
// ACTION_T_CHANGE_MOVEMENT = 48
struct
{
uint32 emoteId;
uint32 targetGuid;
} emoteTarget;
uint32 movementType;
uint32 wanderDistance;
uint32 unused1;
} changeMovement;
// ACTION_T_DYNAMIC_MOVEMENT = 49
struct
{
uint32 state; // bool: 1 = on; 0 = off
uint32 unused1;
uint32 unused2;
} dynamicMovement;
// RAW
struct
{
@ -672,6 +681,8 @@ class CreatureEventAI : public CreatureAI
uint8 m_Phase; // Current phase, max 32 phases
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_throwAIEventMask; // Automatically throw AIEvents that are encoded into this mask

View file

@ -873,6 +873,21 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
continue;
}
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:
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;

View file

@ -119,7 +119,7 @@ namespace MaNGOS
{
if (u->GetTypeId() == TYPEID_UNIT && (
((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;
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;
}
void GameObject::SetCapturePointSlider(float value)
void GameObject::SetCapturePointSlider(float value, bool isLocked)
{
GameObjectInfo const* info = GetGOInfo();
m_captureSlider = value;
// only activate non-locked capture point
if (value >= 0)
{
m_captureSlider = value;
{ SetLootState(GO_ACTIVATED); }
}
else
m_captureSlider = -value;
if (!isLocked)
SetLootState(GO_ACTIVATED);
// set the state of the capture point based on the slider value
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)
{ m_captureState = CAPTURE_STATE_WIN_HORDE; }
m_captureState = CAPTURE_STATE_WIN_HORDE;
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)
{ m_captureState = CAPTURE_STATE_PROGRESS_HORDE; }
m_captureState = CAPTURE_STATE_PROGRESS_HORDE;
else
{ m_captureState = CAPTURE_STATE_NEUTRAL; }
m_captureState = CAPTURE_STATE_NEUTRAL;
}
void GameObject::TickCapturePoint()

View file

@ -622,11 +622,11 @@ enum CapturePointState
CAPTURE_STATE_WIN_HORDE
};
enum CapturePointSlider
enum CapturePointSliderValue
{
CAPTURE_SLIDER_ALLIANCE = 100, // full alliance
CAPTURE_SLIDER_HORDE = 0, // full horde
CAPTURE_SLIDER_MIDDLE = 50 // middle
CAPTURE_SLIDER_ALLIANCE = 100, // full alliance
CAPTURE_SLIDER_HORDE = 0, // full horde
CAPTURE_SLIDER_MIDDLE = 50 // middle
};
class Unit;
@ -796,8 +796,10 @@ class GameObject : public WorldObject
GameObject* LookupFishingHoleAround(float range);
void SetCapturePointSlider(float value);
float GetCapturePointSlider() const { return m_captureSlider; }
void SetCapturePointSlider(float value, bool isLocked);
float GetCapturePointSliderValue() const { return m_captureSlider; }
float GetInteractionDistance();
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))
{
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)
{
@ -600,7 +600,7 @@ void Guild::BroadcastAddonToGuild(WorldSession* session, const std::string& msg,
if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(), GR_RIGHT_GCHATSPEAK))
{
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)
{
@ -614,18 +614,22 @@ void Guild::BroadcastAddonToGuild(WorldSession* session, const std::string& msg,
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;
ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, language, msg.c_str());
WorldPacket data;
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()))
pl->GetSession()->SendPacket(&data);
}
if (pl && pl->GetSession() && HasRankRight(pl->GetRank(), GR_RIGHT_OFFCHATLISTEN) && !pl->GetSocial()->HasIgnore(player->GetObjectGuid()))
pl->GetSession()->SendPacket(&data);
}
}
@ -636,7 +640,7 @@ void Guild::BroadcastAddonToOfficers(WorldSession* session, const std::string& m
for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{
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));

View file

@ -47,11 +47,11 @@ static eConfigFloatValues const qualityToRate[MAX_ITEM_QUALITY] =
LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true);
LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant 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_Mail("mail_loot_template", "mail template id", false);
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_Reference("reference_loot_template", "reference id", false);
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 (uint32 lootid = cInfo->lootid)
if (uint32 Lootid = cInfo->LootId)
{
if (ids_set.find(lootid) == ids_set.end())
LootTemplates_Creature.ReportNotExistedId(lootid);
if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Creature.ReportNotExistedId(Lootid);
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 (uint32 lootid = proto->DisenchantID)
if (uint32 Lootid = proto->DisenchantID)
{
if (ids_set.find(lootid) == ids_set.end())
LootTemplates_Disenchant.ReportNotExistedId(lootid);
if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Disenchant.ReportNotExistedId(Lootid);
else
ids_setUsed.insert(lootid);
ids_setUsed.insert(Lootid);
}
}
}
@ -1344,12 +1344,12 @@ void LoadLootTemplates_Gameobject()
// remove real entries and check existence loot
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())
LootTemplates_Gameobject.ReportNotExistedId(lootid);
if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Gameobject.ReportNotExistedId(Lootid);
else
ids_setUsed.insert(lootid);
ids_setUsed.insert(Lootid);
}
}
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 (uint32 lootid = cInfo->pickpocketLootId)
if (uint32 Lootid = cInfo->PickpocketLootId)
{
if (ids_set.find(lootid) == ids_set.end())
LootTemplates_Pickpocketing.ReportNotExistedId(lootid);
if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Pickpocketing.ReportNotExistedId(Lootid);
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 (uint32 lootid = cInfo->SkinLootId)
if (uint32 Lootid = cInfo->SkinningLootId)
{
if (ids_set.find(lootid) == ids_set.end())
LootTemplates_Skinning.ReportNotExistedId(lootid);
if (ids_set.find(Lootid) == ids_set.end())
LootTemplates_Skinning.ReportNotExistedId(Lootid);
else
ids_setUsed.insert(lootid);
ids_setUsed.insert(Lootid);
}
}
}

View file

@ -49,6 +49,7 @@
#include "TemporarySummon.h"
#include "movement/packet_builder.h"
#include "CreatureLinkingMgr.h"
#include "Chat.h"
#ifdef ENABLE_ELUNA
#include "LuaEngine.h"
#include "ElunaEventMgr.h"
@ -1550,22 +1551,24 @@ bool WorldObject::IsPositionValid() const
void WorldObject::MonsterSay(const char* text, uint32 language, Unit const* target) const
{
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);
}
void WorldObject::MonsterYell(const char* text, uint32 language, Unit const* target) const
{
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);
}
void WorldObject::MonsterTextEmote(const char* text, Unit const* target, bool IsBossEmote) const
{
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, text, LANG_UNIVERSAL,
GetName(), target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : "");
ChatHandler::BuildChatPacket(data, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, text, LANG_UNIVERSAL, CHAT_TAG_NONE, GetObjectGuid(), GetName(),
target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : "");
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; }
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, text, LANG_UNIVERSAL,
GetName(), target->GetObjectGuid(), target->GetName());
ChatHandler::BuildChatPacket(data, IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, text, LANG_UNIVERSAL, CHAT_TAG_NONE, GetObjectGuid(), GetName(),
target->GetObjectGuid(), target->GetName());
((Player*)target)->GetSession()->SendPacket(&data);
}
@ -1584,102 +1587,87 @@ namespace MaNGOS
{
class MonsterChatBuilder
{
public:
MonsterChatBuilder(WorldObject const& obj, ChatMsg msgtype, int32 textId, uint32 language, Unit const* target)
: i_object(obj), i_msgtype(msgtype), i_textId(textId), i_language(language), i_target(target) {}
public:
MonsterChatBuilder(WorldObject const& obj, ChatMsg msgtype, MangosStringLocale const* textData, Language language, Unit const* target)
: i_object(obj), i_msgtype(msgtype), i_textData(textData), i_language(language), i_target(target) {}
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:
WorldObject const& i_object;
ChatMsg i_msgtype;
int32 i_textId;
uint32 i_language;
MangosStringLocale const* i_textData;
Language i_language;
Unit const* i_target;
};
} // 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(*this, CHAT_MSG_MONSTER_SAY, textId, language, target);
MaNGOS::MonsterChatBuilder say_build(*source, msgtype, textData, language, 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);
MaNGOS::CameraDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(source, range, say_do);
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::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId, language, 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);
}
MANGOS_ASSERT(textData);
void WorldObject::MonsterYellToZone(int32 textId, uint32 language, Unit const* target) const
{
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId, language, target);
MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
uint32 zoneid = GetZoneId();
Map::PlayerList const& pList = GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
if (itr->getSource()->GetZoneId() == zoneid)
say_do(itr->getSource());
}
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())
switch (textData->Type)
{
*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);
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);
say_do((Player*)target);
break;
}
case CHAT_TYPE_BOSS_WHISPER:
{
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);
uint32 zoneid = GetZoneId();
Map::PlayerList const& pList = GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
if (itr->getSource()->GetZoneId() == zoneid)
say_do(itr->getSource());
break;
}
}
}

View file

@ -601,16 +601,13 @@ class WorldObject : public Object
virtual void SendMessageToSetInRange(WorldPacket* data, float dist, bool self) const;
void SendMessageToSetExcept(WorldPacket* data, Player const* skipped_receiver) const;
void MonsterSay(const char* text, uint32 language, Unit const* target = NULL) const;
void MonsterYell(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 = nullptr) 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 MonsterSay(int32 textId, uint32 language, Unit const* target = NULL) 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 MonsterText(MangosStringLocale const* textData, 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 PlayDirectSound(uint32 sound_id, Player const* target = NULL) const;

View file

@ -527,38 +527,38 @@ void ObjectMgr::LoadCreatureTemplates()
if (!ok2)
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).",
i, cInfo->unit_class, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->unit_class);
sLog.outErrorDb("Creature (Entry: %u, class %u) has different `UnitClass` in difficulty %u mode (Entry: %u, class %u).",
i, cInfo->UnitClass, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->UnitClass);
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;
}
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;
}
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]);
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;
}
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]);
continue;
@ -630,56 +630,89 @@ void ObjectMgr::LoadCreatureTemplates()
if (!displayScaleEntry)
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);
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);
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->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)
if (cInfo->MinLevel > DEFAULT_MAX_CREATURE_LEVEL)
{
sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`", cInfo->Entry, cInfo->dmgschool);
const_cast<CreatureInfo*>(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL;
sLog.outErrorDb("Creature (Entry: %u) `MinLevel` exceeds maximum allowed value of '%u'", cInfo->Entry, uint32(DEFAULT_MAX_CREATURE_LEVEL));
const_cast<CreatureInfo*>(cInfo)->MinLevel = uint32(DEFAULT_MAX_CREATURE_LEVEL);
}
if (cInfo->baseattacktime == 0)
const_cast<CreatureInfo*>(cInfo)->baseattacktime = BASE_ATTACK_TIME;
if (cInfo->MaxLevel > DEFAULT_MAX_CREATURE_LEVEL)
{
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)
const_cast<CreatureInfo*>(cInfo)->rangeattacktime = BASE_ATTACK_TIME;
if (cInfo->Expansion > MAX_EXPANSION)
{
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);
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)
sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u", cInfo->Entry, cInfo->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->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);
const_cast<CreatureInfo*>(cInfo)->type = CREATURE_TYPE_HUMANOID;
sLog.outErrorDb("Creature (Entry: %u) has invalid creature type (%u) in `type`", cInfo->Entry, cInfo->CreatureType);
const_cast<CreatureInfo*>(cInfo)->CreatureType = CREATURE_TYPE_HUMANOID;
}
// 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);
const_cast<CreatureInfo*>(cInfo)->family = 0;
sLog.outErrorDb("Creature (Entry: %u) has invalid creature family (%u) in `Family`", cInfo->Entry, cInfo->Family);
const_cast<CreatureInfo*>(cInfo)->Family = 0;
}
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))
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);
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->VendorTemplateId, UNIT_NPC_FLAG_VENDOR);
}
/// 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);
}
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()
{
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);
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->MinLevelHealth;
}
if (cInfo->ExtraFlags & CREATURE_FLAG_EXTRA_INSTANCE_BIND)
if (cInfo->ExtraFlags & CREATURE_EXTRA_FLAG_INSTANCE_BIND)
{
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.",
guid, data.id, CREATURE_FLAG_EXTRA_INSTANCE_BIND);
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_EXTRA_FLAG_INSTANCE_BIND);
}
if (cInfo->ExtraFlags & CREATURE_FLAG_EXTRA_AGGRO_ZONE)
if (cInfo->ExtraFlags & CREATURE_EXTRA_FLAG_AGGRO_ZONE)
{
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.",
guid, data.id, CREATURE_FLAG_EXTRA_AGGRO_ZONE);
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_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);
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->MinLevelMana;
}
if (data.spawndist < 0.0f)
@ -6601,7 +6647,7 @@ std::string ObjectMgr::GeneratePetName(uint32 entry)
if (list0.empty() || list1.empty())
{
CreatureInfo const* cinfo = GetCreatureTemplate(entry);
char const* petname = GetPetName(cinfo->family, sWorld.GetDefaultDbcLocale());
char const* petname = GetPetName(cinfo->Family, sWorld.GetDefaultDbcLocale());
if (!petname)
petname = cinfo->Name;
return std::string(petname);
@ -7340,7 +7386,7 @@ void ObjectMgr::LoadNPCSpellClickSpells()
mSpellClickInfoMap.insert(SpellClickInfoMap::value_type(npc_entry, info));
// 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;
}
@ -7544,8 +7590,8 @@ void ObjectMgr::LoadCreatureQuestRelations()
CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
if (!cInfo)
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))
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);
else if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_QUESTGIVER))
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);
if (!cInfo)
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))
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);
else if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_QUESTGIVER))
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);
}
}
@ -7997,10 +8043,10 @@ bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min
// Load additional string content if necessary
if (extra_content)
{
data.SoundId = fields[10].GetUInt32();
data.Type = fields[11].GetUInt32();
data.LanguageId = (Language)fields[12].GetUInt32();
data.Emote = fields[13].GetUInt32();
data.SoundId = fields[10].GetUInt32();
data.Type = fields[11].GetUInt32();
data.LanguageId = Language(fields[12].GetUInt32());
data.Emote = fields[13].GetUInt32();
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))
{
_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;
}
@ -9237,7 +9283,7 @@ void ObjectMgr::LoadTrainers(char const* tableName, bool isTemplates)
continue;
}
if (!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER))
if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_TRAINER))
{
if (skip_trainers.find(entry) == skip_trainers.end())
{
@ -9247,11 +9293,11 @@ void ObjectMgr::LoadTrainers(char const* tableName, bool isTemplates)
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())
{
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;
}
}
@ -9349,12 +9395,12 @@ void ObjectMgr::LoadTrainerTemplates()
{
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
{
if (cInfo->trainerId)
if (cInfo->TrainerTemplateId)
{
if (m_mCacheTrainerTemplateSpellMap.find(cInfo->trainerId) != m_mCacheTrainerTemplateSpellMap.end())
trainer_ids.erase(cInfo->trainerId);
if (m_mCacheTrainerTemplateSpellMap.find(cInfo->TrainerTemplateId) != m_mCacheTrainerTemplateSpellMap.end())
trainer_ids.erase(cInfo->TrainerTemplateId);
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 (cInfo->vendorId)
if (cInfo->VendorTemplateId)
{
if (m_mCacheVendorTemplateItemMap.find(cInfo->vendorId) != m_mCacheVendorTemplateItemMap.end())
vendor_ids.erase(cInfo->vendorId);
if (m_mCacheVendorTemplateItemMap.find(cInfo->VendorTemplateId) != m_mCacheVendorTemplateItemMap.end())
vendor_ids.erase(cInfo->VendorTemplateId);
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();
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, "
"condition_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_text = fields[3].GetCppString();
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_poi_id = fields[7].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)
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_flags_uses = false;
@ -9706,12 +9752,12 @@ void ObjectMgr::LoadGossipMenuItems(std::set<uint32>& gossipScriptSet)
found_menu_uses = true;
// 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;
}
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))
@ -9820,7 +9866,7 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
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)
{
@ -9923,12 +9969,12 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
}
else
{
if (!cInfo->vendorId)
if (!cInfo->VendorTemplateId)
sLog.outErrorDb("Table `%s` has duplicate items %u for %s %u, ignoring",
tableName, item_id, idStr, vendor_entry);
else
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;
}
@ -9974,7 +10020,7 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
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)
{
@ -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);
else
{
if (!cInfo->vendorId)
if (!cInfo->VendorTemplateId)
sLog.outErrorDb("Table `%s` has duplicate %s %u (with extended cost %u) for %s %u, ignoring",
tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry);
else
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;
}
@ -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);
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;
_DoStringError(entry, "DoDisplayText entry %i cannot whisper without target unit (TYPEID_PLAYER).", entry);
return false;
}
source->MonsterText(data, target);
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 MAX_MANGOS_STRING_ID 2000000000
#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 MAX_CREATURE_AI_TEXT_STRING_ID (-1000000)
// Anything below MAX_CREATURE_AI_TEXT_STRING_ID is handled by the external script lib
@ -283,7 +283,7 @@ struct GossipMenuItems
uint8 option_icon;
std::string option_text;
uint32 option_id;
uint32 npc_option_npcflag;
uint32 npc_option_NpcFlags;
int32 action_menu_id;
uint32 action_poi_id;
uint32 action_script_id;
@ -1191,6 +1191,19 @@ class ObjectMgr
QuestRelationsMap& GetCreatureQuestRelationsMap() { return m_CreatureQuestRelations; }
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();
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
CreatureInfo const* cinfo = GetCreatureInfo();
if (cinfo->type == CREATURE_TYPE_CRITTER)
if (cinfo->CreatureType == CREATURE_TYPE_CRITTER)
{
AIM_Initialize();
pos.GetMap()->Add((Creature*)this);
@ -817,7 +817,7 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
return false;
}
if (cinfo->type == CREATURE_TYPE_CRITTER)
if (cinfo->CreatureType == CREATURE_TYPE_CRITTER)
{
setPetType(MINI_PET);
return true;
@ -830,12 +830,12 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr.GetXPForPetLevel(creature->getLevel()));
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()]);
else
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, 2, GENDER_NONE);
@ -889,7 +889,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
SetLevel(petlevel);
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
SetMeleeDamageSchool(SpellSchools(cinfo->DamageSchool));
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);
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family);
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->Family);
if (cFamily && cFamily->minScale > 0.0f && getPetType() == HUNTER_PET)
{
float Scale;
@ -919,12 +919,12 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
if (getPetType() != HUNTER_PET)
{
createResistance[SPELL_SCHOOL_HOLY] = cinfo->resistance1;
createResistance[SPELL_SCHOOL_FIRE] = cinfo->resistance2;
createResistance[SPELL_SCHOOL_NATURE] = cinfo->resistance3;
createResistance[SPELL_SCHOOL_FROST] = cinfo->resistance4;
createResistance[SPELL_SCHOOL_SHADOW] = cinfo->resistance5;
createResistance[SPELL_SCHOOL_ARCANE] = cinfo->resistance6;
createResistance[SPELL_SCHOOL_HOLY] = cinfo->ResistanceHoly;
createResistance[SPELL_SCHOOL_FIRE] = cinfo->ResistanceFire;
createResistance[SPELL_SCHOOL_NATURE] = cinfo->ResistanceNature;
createResistance[SPELL_SCHOOL_FROST] = cinfo->ResistanceFrost;
createResistance[SPELL_SCHOOL_SHADOW] = cinfo->ResistanceShadow;
createResistance[SPELL_SCHOOL_ARCANE] = cinfo->ResistanceArcane;
}
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);
// remove elite bonuses included in DB values
SetCreateHealth(uint32(((float(cinfo->maxhealth) / cinfo->maxlevel) / (1 + 2 * cinfo->Rank)) * petlevel));
SetCreateMana(uint32(((float(cinfo->maxmana) / cinfo->maxlevel) / (1 + 2 * cinfo->Rank)) * petlevel));
SetCreateHealth(uint32(((float(cinfo->MaxLevelHealth) / 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_AGILITY, 22);
@ -1024,7 +1024,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
sLog.outErrorDb("Hunter pet levelstats missing in DB");
// 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_AGILITY, 22);
@ -1074,7 +1074,7 @@ bool Pet::HaveInDiet(ItemPrototype const* item) const
if (!cInfo)
return false;
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->family);
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->Family);
if (!cFamily)
return false;
@ -1563,7 +1563,7 @@ void Pet::InitLevelupSpellsForLevel()
{
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
for (PetLevelupSpellSet::const_reverse_iterator itr = levelupSpells->rbegin(); itr != levelupSpells->rend(); ++itr)
@ -1702,7 +1702,7 @@ bool Pet::resetTalents(bool no_cost)
if (!ci)
return false;
// 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)
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
// i.e. does not unsummon at mounting, gets dismissed at teleport etc.
case CLASS_WARLOCK:
return GetCreatureInfo()->type == CREATURE_TYPE_DEMON;
return GetCreatureInfo()->CreatureType == CREATURE_TYPE_DEMON;
case CLASS_DEATH_KNIGHT:
return GetCreatureInfo()->type == CREATURE_TYPE_UNDEAD;
return GetCreatureInfo()->CreatureType == CREATURE_TYPE_UNDEAD;
default:
return false;
}
@ -2012,7 +2012,7 @@ void Pet::LearnPetPassives()
if (!cInfo)
return;
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->family);
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->Family);
if (!cFamily)
return;

View file

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

View file

@ -1526,7 +1526,7 @@ bool Player::BuildEnumData(QueryResult* result, ByteBuffer* data, ByteBuffer* bu
{
petDisplayId = fields[17].GetUInt32();
petLevel = fields[18].GetUInt32();
petFamily = cInfo->family;
petFamily = cInfo->Family;
}
}
@ -1644,9 +1644,9 @@ void Player::ToggleDND()
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())
tag |= CHAT_TAG_AFK;
@ -2291,7 +2291,7 @@ void Player::RegenerateHealth(uint32 diff)
ModifyHealth(int32(addvalue));
}
Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask)
Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 NpcFlagsmask)
{
// some basic checks
if (!guid || !IsInWorld() || IsTaxiFlying())
@ -2307,10 +2307,10 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask)
return NULL;
// appropriate npc type
if (npcflagmask && !unit->HasFlag(UNIT_NPC_FLAGS, npcflagmask))
if (NpcFlagsmask && !unit->HasFlag(UNIT_NPC_FLAGS, NpcFlagsmask))
return NULL;
if (npcflagmask == UNIT_NPC_FLAG_STABLEMASTER)
if (NpcFlagsmask == UNIT_NPC_FLAG_STABLEMASTER)
{
if (getClass() != CLASS_HUNTER)
return NULL;
@ -5047,7 +5047,7 @@ void Player::CleanupChannels()
{
Channel* ch = *m_channels.begin();
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()))
cMgr->LeftChannel(ch->GetName()); // deleted channel if empty
}
@ -5091,13 +5091,13 @@ void Player::UpdateLocalChannels(uint32 newZone)
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
(*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
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!");
@ -5109,7 +5109,7 @@ void Player::LeaveLFGChannel()
{
if ((*i)->IsLFG())
{
(*i)->Leave(GetObjectGuid());
(*i)->Leave(this);
break;
}
}
@ -8120,7 +8120,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
// generate loot only if ready for open and spawned in world
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 (BattleGround* bg = GetBattleGround())
@ -8149,11 +8149,11 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
loot->FillLoot(zone, LootTemplates_Fishing, this, true);
break;
default:
if (!lootid)
if (!Lootid)
break;
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);
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;
loot->clear();
if (uint32 lootid = creature->GetCreatureInfo()->pickpocketLootId)
loot->FillLoot(lootid, LootTemplates_Pickpocketing, this, false);
if (uint32 Lootid = creature->GetCreatureInfo()->PickpocketLootId)
loot->FillLoot(Lootid, LootTemplates_Pickpocketing, this, false);
// Generate extra money for pick pocket loot
const uint32 a = urand(0, creature->getLevel() / 2);
@ -8344,10 +8344,10 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
creature->lootForBody = true;
loot->clear();
if (uint32 lootid = creature->GetCreatureInfo()->lootid)
loot->FillLoot(lootid, LootTemplates_Creature, recipient, false);
if (uint32 Lootid = creature->GetCreatureInfo()->LootId)
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())
{
@ -8378,7 +8378,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
{
creature->lootForSkin = true;
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.
if (!loot->empty())
@ -8474,302 +8474,6 @@ void Player::SendUpdateWorldState(uint32 Field, uint32 Value)
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)
{
// data depends on zoneid/mapid...
@ -8787,136 +8491,53 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
size_t count_pos = data.wpos();
data << uint16(0); // count of uint64 blocks, placeholder
// common fields
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
// Current arena season
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, 0xED9, 1); // 3801 9 0 - Battle for Wintergrasp in progress, 1 - otherwise
// 4354 10 Time when next Battle for Wintergrasp starts
FillInitialWorldState(data, count, 0x1102, uint32(time(NULL) + 9000));
if (mapid == 530) // Outland
{
FillInitialWorldState(data, count, 0x9bf, 0x0); // 2495
FillInitialWorldState(data, count, 0x9bd, 0xF); // 2493
FillInitialWorldState(data, count, 0x9bb, 0xF); // 2491
}
// 0 - Battle for Wintergrasp in progress, 1 - otherwise
FillInitialWorldState(data, count, 0xED9, 1);
// Time when next Battle for Wintergrasp starts
FillInitialWorldState(data, count, 0x1102, uint32(time(nullptr) + 9000));
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
if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid))
outdoorPvP->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, EP_world_states);
break;
case 1377: // Silithus
case 3483: // Hellfire Peninsula
case 3518: // Nagrand
case 3519: // Terokkar Forest
case 3521: // Zangarmarsh
if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid))
outdoorPvP->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, SI_world_states);
break;
case 2597: // AV
if (bg && bg->GetTypeID() == BATTLEGROUND_AV)
bg->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, AV_world_states);
break;
case 3277: // WS
if (bg && bg->GetTypeID() == BATTLEGROUND_WS)
bg->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, WS_world_states);
break;
case 3358: // AB
if (bg && bg->GetTypeID() == BATTLEGROUND_AB)
bg->FillInitialWorldStates(data, count);
else
FillInitialWorldState(data, count, AB_world_states);
break;
case 3820: // EY
if (bg && bg->GetTypeID() == BATTLEGROUND_EY)
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;
case 3698: // Nagrand Arena
if (bg && bg->GetTypeID() == BATTLEGROUND_NA)
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;
case 3702: // Blade's Edge Arena
if (bg && bg->GetTypeID() == BATTLEGROUND_BE)
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;
case 3968: // Ruins of Lordaeron
if (bg && bg->GetTypeID() == BATTLEGROUND_RL)
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;
}
@ -13093,9 +12714,9 @@ void Player::PrepareGossipMenu(WorldObject* pSource, uint32 menuId)
{
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;
switch (itr->second.option_id)
@ -13126,7 +12747,7 @@ void Player::PrepareGossipMenu(WorldObject* pSource, uint32 menuId)
case GOSSIP_OPTION_TRAINER:
// pet trainers not have spells in fact now
/* 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;
else */
if (!pCreature->IsTrainerOf(this, false))
@ -13137,7 +12758,7 @@ void Player::PrepareGossipMenu(WorldObject* pSource, uint32 menuId)
hasMenuItem = false;
break;
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;
else if (Pet* pet = GetPet())
{
@ -18660,39 +18281,24 @@ void Player::RemovePet(PetSaveMode mode)
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)
{
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_SAY, text, language);
WorldPacket data;
ChatHandler::BuildChatPacket(data, CHAT_MSG_SAY, text.c_str(), Language(language), GetChatTag(), GetObjectGuid(), GetName());
SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY), true);
}
void Player::Yell(const std::string& text, const uint32 language)
{
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_YELL, text, language);
WorldPacket data;
ChatHandler::BuildChatPacket(data, CHAT_MSG_YELL, text.c_str(), Language(language), GetChatTag(), GetObjectGuid(), GetName());
SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL), true);
}
void Player::TextEmote(const std::string& text)
{
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_EMOTE, text, LANG_UNIVERSAL);
WorldPacket data;
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));
}
@ -18700,12 +18306,12 @@ void Player::Whisper(const std::string& text, uint32 language, ObjectGuid receiv
{
Player* rPlayer = sObjectMgr.GetPlayer(receiver);
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_WHISPER, text, language);
WorldPacket data;
ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, text.c_str(), Language(language), GetChatTag(), GetObjectGuid(), GetName());
rPlayer->GetSession()->SendPacket(&data);
data.Initialize(SMSG_MESSAGECHAT, 200);
rPlayer->BuildPlayerChat(&data, CHAT_MSG_WHISPER_INFORM, text, language);
data.clear();
ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER_INFORM, text.c_str(), Language(language), CHAT_TAG_NONE, rPlayer->GetObjectGuid());
GetSession()->SendPacket(&data);
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());
}
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()
{
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);
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 << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0);
@ -18862,7 +18457,7 @@ void Player::CharmSpellInitialize()
{
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)
{
@ -21486,7 +21081,7 @@ bool Player::isHonorOrXPTarget(Unit* pVictim) const
{
if (((Creature*)pVictim)->IsTotem() ||
((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 true;
@ -22808,7 +22403,7 @@ void Player::LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRa
if (!ci)
return;
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family);
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->Family);
if (!pet_family)
return;
@ -23033,7 +22628,7 @@ void Player::BuildPetTalentsInfoData(WorldPacket* data)
if (!ci)
return;
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family);
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->Family);
if (!pet_family || pet_family->petTalentType < 0)
return;

View file

@ -43,6 +43,7 @@
#include "ReputationMgr.h"
#include "BattleGround.h"
#include "SharedDefines.h"
#include "Chat.h"
#include<string>
#include<vector>
@ -1111,20 +1112,15 @@ class Player : public Unit
void SendInitialPacketsAfterAddToMap();
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;
void ToggleAFK();
void ToggleDND();
bool isAFK() const
{
return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK);
}
bool isDND() const
{
return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND);
}
uint8 GetChatTag() const;
bool isAFK() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); }
bool isDND() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND); }
ChatTagFlags GetChatTag() const;
std::string autoReplyMsg;
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 TextEmote(const std::string& text);
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 ***/

View file

@ -757,10 +757,16 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
case 18153: // Kodo Kombobulator
case 32312: // Move 1
case 37388: // Move 2
case 45863: // Cosmetic - Incinerate to Random Target
case 49634: // Sergeant's Flare
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 63745: // Sara's Blessing
case 63747: // Sara's Fervor
case 64402: // Rocket Strike
return true;
default:
break;
@ -2220,6 +2226,11 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
if ((spellInfo_1->Id == 62169 && spellInfo_2->Id == 64417) ||
(spellInfo_2->Id == 62169 && spellInfo_1->Id == 64417))
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;
}
case SPELLFAMILY_MAGE:
@ -3523,9 +3534,9 @@ void SpellMgr::LoadSpellScriptTarget()
}
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);
continue;
}
@ -3710,7 +3721,7 @@ bool SpellMgr::LoadPetDefaultSpells_helper(CreatureInfo const* cInfo, PetDefault
return false;
// 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)
{

View file

@ -883,12 +883,12 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType)
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 */
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_pct = GetModifierValue(unitMod, BASE_PCT);
float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
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_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);

View file

@ -902,48 +902,11 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
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");
uint32 health = pVictim->GetHealth();
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)
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)
{
Player* killer = ((Player*)this);
@ -1208,11 +1235,6 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
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)
{
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 != DOT)
@ -1426,7 +1433,7 @@ void Unit::JustKilledCreature(Creature* victim, Player* responsiblePlayer)
{
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); }
}
else
@ -1779,7 +1786,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss)
}
// 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->target = pVictim;
@ -1836,7 +1843,7 @@ void Unit::CalculateMeleeDamage(Unit* pVictim, uint32 damage, CalcDamageInfo* da
damageInfo->cleanDamage = 0;
return;
}
damage += CalculateDamage(damageInfo->attackType, false);
uint32 damage = CalculateDamage(damageInfo->attackType, false);
// Add melee damage bonus
damage = MeleeDamageBonusDone(damageInfo->target, 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);
CalcDamageInfo damageInfo;
CalculateMeleeDamage(pVictim, 0, &damageInfo, attType);
CalculateMeleeDamage(pVictim, &damageInfo, attType);
// Send log damage message to client
DealDamageMods(pVictim, damageInfo.damage, &damageInfo.absorb);
SendAttackStateUpdate(&damageInfo);
@ -3028,7 +3035,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* pVictim, WeaponAttackT
else
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;
@ -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
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;
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 &&
// can be from by creature (if can) or from controlled player that considered as creature
((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()))
{
// 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
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;
}
@ -3363,7 +3370,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* pVictim, SpellEntry const* spell)
if (pVictim->GetTypeId() == TYPEID_UNIT)
{
uint32 flagEx = ((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags;
if (flagEx & CREATURE_FLAG_EXTRA_NO_PARRY)
if (flagEx & CREATURE_EXTRA_FLAG_NO_PARRY)
canParry = false;
}
// Ignore combat result aura
@ -6225,6 +6232,26 @@ bool Unit::isAttackingPlayer() const
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()
{
while (!m_attackers.empty())
@ -8431,7 +8458,7 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy)
{ pCreature->AI()->EnterCombat(enemy); }
// 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(); }
if (InstanceData* mapInstance = GetInstanceData())
@ -8466,7 +8493,7 @@ void Unit::ClearInCombat()
if (GetTypeId() == TYPEID_UNIT)
{
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);
clearUnitState(UNIT_STAT_ATTACK_PLAYER);
@ -8968,10 +8995,10 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced, float ratio, bool ignore
switch (mtype)
{
case MOVE_RUN:
speed *= ((Creature*)this)->GetCreatureInfo()->speed_run;
speed *= ((Creature*)this)->GetCreatureInfo()->SpeedRun;
break;
case MOVE_WALK:
speed *= ((Creature*)this)->GetCreatureInfo()->speed_walk;
speed *= ((Creature*)this)->GetCreatureInfo()->SpeedWalk;
break;
default:
break;
@ -9900,7 +9927,7 @@ uint32 Unit::GetCreatureType() const
return CREATURE_TYPE_HUMANOID;
}
else
return ((Creature*)this)->GetCreatureInfo()->type;
return ((Creature*)this)->GetCreatureInfo()->CreatureType;
}
/*#######################################
@ -10816,76 +10843,91 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* pTarget, uint32 procFlag,
if (itr->second->IsDeleted())
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))
{
// 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;
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
procTriggered.push_back(ProcTriggeredData(spellProcEvent, itr->second));
}
// Nothing found
if (procTriggered.empty())
return;
// Handle effects proceed this time
for (ProcTriggeredList::const_iterator itr = procTriggered.begin(); itr != procTriggered.end(); ++itr)
if (!procTriggered.empty())
{
// Some auras can be deleted in function called in this loop (except first, ofc)
SpellAuraHolder* triggeredByHolder = itr->triggeredByHolder;
if (triggeredByHolder->IsDeleted())
continue;
SpellProcEventEntry const* spellProcEvent = itr->spellProcEvent;
bool useCharges = triggeredByHolder->GetAuraCharges() > 0;
bool procSuccess = true;
bool anyAuraProc = false;
// For players set spell cooldown if need
uint32 cooldown = 0;
if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->cooldown)
cooldown = spellProcEvent->cooldown;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
// Handle effects proceed this time
for (ProcTriggeredList::const_iterator itr = procTriggered.begin(); itr != procTriggered.end(); ++itr)
{
Aura* triggeredByAura = triggeredByHolder->GetAuraByEffectIndex(SpellEffectIndex(i));
if (!triggeredByAura)
// Some auras can be deleted in function called in this loop (except first, ofc)
SpellAuraHolder* triggeredByHolder = itr->triggeredByHolder;
if (triggeredByHolder->IsDeleted())
continue;
SpellEffectEntry const* spellEffect = triggeredByHolder->GetSpellProto()->GetSpellEffect(SpellEffectIndex(i));
if (!spellEffect)
continue;
SpellProcEventEntry const* spellProcEvent = itr->spellProcEvent;
bool useCharges = triggeredByHolder->GetAuraCharges() > 0;
bool procSuccess = true;
bool anyAuraProc = false;
if (procSpell)
// For players set spell cooldown if need
uint32 cooldown = 0;
if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->cooldown)
cooldown = spellProcEvent->cooldown;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if (spellProcEvent)
{
if (spellProcEvent->spellFamilyMask[i])
{
if (!procSpell->IsFitToFamilyMask(spellProcEvent->spellFamilyMask[i]))
continue;
Aura* triggeredByAura = triggeredByHolder->GetAuraByEffectIndex(SpellEffectIndex(i));
if (!triggeredByAura)
continue;
// don't allow proc from cast end for non modifier spells
// unless they have proc ex defined for that
if (IsCastEndProcModifierAura(triggeredByHolder->GetSpellProto(), SpellEffectIndex(i), procSpell))
SpellEffectEntry const* spellEffect = triggeredByHolder->GetSpellProto()->GetSpellEffect(SpellEffectIndex(i));
if (!spellEffect)
continue;
if (procSpell)
{
if (spellProcEvent)
{
if (spellProcEvent->spellFamilyMask[i])
{
if (useCharges && procExtra != PROC_EX_CAST_END && spellProcEvent->procEx == PROC_EX_NONE)
if (!procSpell->IsFitToFamilyMask(spellProcEvent->spellFamilyMask[i]))
continue;
// don't allow proc from cast end for non modifier spells
// unless they have proc ex defined for that
if (IsCastEndProcModifierAura(triggeredByHolder->GetSpellProto(), SpellEffectIndex(i), procSpell))
{
if (useCharges && procExtra != PROC_EX_CAST_END && spellProcEvent->procEx == PROC_EX_NONE)
continue;
}
else if (spellProcEvent->procEx == PROC_EX_NONE && procExtra == PROC_EX_CAST_END)
continue;
}
else if (spellProcEvent->procEx == PROC_EX_NONE && procExtra == PROC_EX_CAST_END)
// don't check dbc FamilyFlags if schoolMask exists
else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, spellProcEvent->procEx, procExtra, damage != 0, !spellProcEvent->schoolMask))
continue;
}
// don't check dbc FamilyFlags if schoolMask exists
else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, spellProcEvent->procEx, procExtra, damage != 0, !spellProcEvent->schoolMask))
else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, PROC_EX_NONE, procExtra, damage != 0, true))
continue;
}
else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, PROC_EX_NONE, procExtra, damage != 0, true))
continue;
}
SpellAuraProcResult procResult = (*this.*AuraProcHandler[spellEffect->EffectApplyAuraName])(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown);
switch (procResult)
{
SpellAuraProcResult procResult = (*this.*AuraProcHandler[spellEffect->EffectApplyAuraName])(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown);
switch (procResult)
{
case SPELL_AURA_PROC_CANT_TRIGGER:
continue;
case SPELL_AURA_PROC_FAILED:
@ -10893,20 +10935,21 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* pTarget, uint32 procFlag,
break;
case SPELL_AURA_PROC_OK:
break;
}
anyAuraProc = true;
}
anyAuraProc = true;
}
// Remove charge (aura can be removed by triggers)
if (useCharges && procSuccess && anyAuraProc && !triggeredByHolder->IsDeleted())
{
// If last charge dropped add spell to remove list
if (triggeredByHolder->DropAuraCharge())
removedSpells.push_back(triggeredByHolder->GetId());
}
// Remove charge (aura can be removed by triggers)
if (useCharges && procSuccess && anyAuraProc && !triggeredByHolder->IsDeleted())
{
// If last charge dropped add spell to remove list
if (triggeredByHolder->DropAuraCharge())
removedSpells.push_back(triggeredByHolder->GetId());
triggeredByHolder->SetInUse(false);
}
triggeredByHolder->SetInUse(false);
}
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_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
#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.
*/
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
*/
@ -2120,7 +2137,7 @@ class Unit : public WorldObject
* @param damageInfo this is filled with data about what kind of damage that was done
* @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
* 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
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)
{
// save capture point slider value (negative value if locked)
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

@ -48,7 +48,7 @@ enum CapturePointAnimations
CAPTURE_ANIM_NEUTRAL = 2
};
typedef std::map < ObjectGuid /*playerGuid*/, bool /*isMainZone*/ > GuidZoneMap;
typedef std::map<ObjectGuid /*playerGuid*/, bool /*isMainZone*/> GuidZoneMap;
class OutdoorPvP
{
@ -65,7 +65,7 @@ class OutdoorPvP
virtual bool HandleEvent(uint32 /*eventId*/, GameObject* /*go*/) { return false; }
// 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
virtual void HandleCreatureCreate(Creature* /*creature*/) {}

View file

@ -148,38 +148,38 @@ 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;
switch (eventId)
{
case EVENT_CROWNGUARD_PROGRESS_ALLIANCE:
case EVENT_CROWNGUARD_PROGRESS_HORDE:
credit = NPC_CROWNGUARD_TOWER_QUEST_DOODAD;
break;
case EVENT_EASTWALL_PROGRESS_ALLIANCE:
case EVENT_EASTWALL_PROGRESS_HORDE:
credit = NPC_EASTWALL_TOWER_QUEST_DOODAD;
break;
case EVENT_NORTHPASS_PROGRESS_ALLIANCE:
case EVENT_NORTHPASS_PROGRESS_HORDE:
credit = NPC_NORTHPASS_TOWER_QUEST_DOODAD;
break;
case EVENT_PLAGUEWOOD_PROGRESS_ALLIANCE:
case EVENT_PLAGUEWOOD_PROGRESS_HORDE:
credit = NPC_PLAGUEWOOD_TOWER_QUEST_DOODAD;
break;
default:
return;
case EVENT_CROWNGUARD_PROGRESS_ALLIANCE:
case EVENT_CROWNGUARD_PROGRESS_HORDE:
credit = NPC_CROWNGUARD_TOWER_QUEST_DOODAD;
break;
case EVENT_EASTWALL_PROGRESS_ALLIANCE:
case EVENT_EASTWALL_PROGRESS_HORDE:
credit = NPC_EASTWALL_TOWER_QUEST_DOODAD;
break;
case EVENT_NORTHPASS_PROGRESS_ALLIANCE:
case EVENT_NORTHPASS_PROGRESS_HORDE:
credit = NPC_NORTHPASS_TOWER_QUEST_DOODAD;
break;
case EVENT_PLAGUEWOOD_PROGRESS_ALLIANCE:
case EVENT_PLAGUEWOOD_PROGRESS_HORDE:
credit = NPC_PLAGUEWOOD_TOWER_QUEST_DOODAD;
break;
default:
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)
{
(*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;
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 HandleGameObjectCreate(GameObject* go) override;

View file

@ -143,16 +143,22 @@ void OutdoorPvPGH::LockLighthouse(const WorldObject* objRef)
if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint))
go->SetLootState(GO_JUST_DEACTIVATED);
else
{
// 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
void OutdoorPvPGH::UnlockLighthouse(const WorldObject* objRef)
{
if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint))
go->SetCapturePointSlider(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE);
go->SetLootState(GO_ACTIVATED);
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;
@ -136,12 +136,12 @@ void OutdoorPvPHP::HandleObjectiveComplete(uint32 eventId, std::list<Player*> pl
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)
{
(*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;
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 HandlePlayerKillInsideArea(Player* player) override;

View file

@ -167,19 +167,3 @@ void OutdoorPvPMgr::Update(uint32 diff)
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
};
struct CapturePointSlider
{
CapturePointSlider() : Value(0.0f), IsLocked(false) {}
CapturePointSlider(float value, bool isLocked) : Value(value), IsLocked(isLocked) {}
float Value;
bool IsLocked;
};
class Player;
class GameObject;
class Creature;
class OutdoorPvP;
typedef std::map<uint32 /*capture point entry*/, CapturePointSlider /*slider value and lock state*/> CapturePointSliderMap;
class OutdoorPvPMgr
{
public:
@ -104,23 +115,21 @@ class OutdoorPvPMgr
void Update(uint32 diff);
// Save and load capture point slider values
float GetCapturePointSliderValue(uint32 entry, float defaultValue);
void SetCapturePointSlider(uint32 entry, float value) { m_capturePointSlider[entry] = value; }
// Save and load capture point slider
CapturePointSliderMap const* GetCapturePointSliderMap() const { return &m_capturePointSlider; }
void SetCapturePointSlider(uint32 entry, CapturePointSlider value) { m_capturePointSlider[entry] = value; }
private:
// return assigned outdoor pvp script
OutdoorPvP* GetScriptOfAffectedZone(uint32 zoneId);
private:
// return assigned outdoor pvp script
OutdoorPvP* GetScriptOfAffectedZone(uint32 zoneId);
// contains all outdoor pvp scripts
OutdoorPvP* m_scripts[MAX_OPVP_ID];
// contains all outdoor pvp scripts
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
ShortIntervalTimer m_updateTimer;
// update interval
ShortIntervalTimer m_updateTimer;
};
#define sOutdoorPvPMgr MaNGOS::Singleton<OutdoorPvPMgr>::Instance()

View file

@ -85,11 +85,11 @@ void OutdoorPvPNA::HandlePlayerLeaveZone(Player* player, bool 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)
{
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)
(*itr)->KilledMonsterCredit(NPC_HALAA_COMBATANT);
@ -550,16 +550,22 @@ void OutdoorPvPNA::LockHalaa(const WorldObject* objRef)
if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint))
go->SetLootState(GO_JUST_DEACTIVATED);
else
{
// 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
void OutdoorPvPNA::UnlockHalaa(const WorldObject* objRef)
{
if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint))
go->SetCapturePointSlider(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE);
go->SetLootState(GO_ACTIVATED);
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;
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 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)
{
@ -126,7 +126,7 @@ void OutdoorPvPTF::HandleObjectiveComplete(uint32 eventId, std::list<Player*> pl
{
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)
(*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]))
go->SetLootState(GO_JUST_DEACTIVATED);
else
{
// 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]))
{
go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE);
go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE, false);
// visual update needed because banner still has artkit from previous owner
SetBannerVisual(go, CAPTURE_ARTKIT_NEUTRAL, CAPTURE_ANIM_NEUTRAL);
}
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;
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 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 };
// 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
#define SPELL_RIDE_VEHICLE_HARDCODED 46598

View file

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

View file

@ -246,12 +246,13 @@ bool AccountMgr::CheckPassword(uint32 accid, std::string passwd)
bool AccountMgr::normalizeString(std::string& utf8str)
{
wchar_t wstr_buf[MAX_ACCOUNT_STR + 1];
size_t wstr_len = MAX_ACCOUNT_STR;
if (!Utf8toWStr(utf8str, wstr_buf, wstr_len))
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);
}

View file

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

File diff suppressed because it is too large Load diff

View file

@ -39,9 +39,9 @@ enum ChatNotify
{
CHAT_JOINED_NOTICE = 0x00, //+ "%s joined channel.";
CHAT_LEFT_NOTICE = 0x01, //+ "%s left channel.";
// CHAT_SUSPENDED_NOTICE = 0x01, // "%s left channel.";
// CHAT_SUSPENDED_NOTICE = 0x01, // "%s left channel.";
CHAT_YOU_JOINED_NOTICE = 0x02, //+ "Joined Channel: [%s]"; -- You joined
// CHAT_YOU_CHANGED_NOTICE = 0x02, // "Changed Channel: [%s]";
// CHAT_YOU_CHANGED_NOTICE = 0x02, // "Changed Channel: [%s]";
CHAT_YOU_LEFT_NOTICE = 0x03, //+ "Left Channel: [%s]"; -- You left
CHAT_WRONG_PASSWORD_NOTICE = 0x04, //+ "Wrong password for %s.";
CHAT_NOT_MEMBER_NOTICE = 0x05, //+ "Not on channel %s.";
@ -63,7 +63,7 @@ enum ChatNotify
CHAT_PLAYER_UNBANNED_NOTICE = 0x15, //? "[%s] Player %s unbanned by %s.";
CHAT_PLAYER_NOT_BANNED_NOTICE = 0x16, //+ "[%s] Player %s is not banned.";
CHAT_PLAYER_ALREADY_MEMBER_NOTICE = 0x17, //+ "[%s] Player %s is already on the channel.";
CHAT_INVITE_NOTICE = 0x18, //+ "%2$s has invited you to join the channel '%1$s'.";
CHAT_INVITE_NOTICE = 0x18, //+ "%2$s has invited you to join the channel '%1$s'.";
CHAT_INVITE_WRONG_FACTION_NOTICE = 0x19, //+ "Target is in the wrong alliance for %s.";
CHAT_WRONG_FACTION_NOTICE = 0x1A, //+ "Wrong alliance for %s.";
CHAT_INVALID_NAME_NOTICE = 0x1B, //+ "Invalid channel name";
@ -75,215 +75,215 @@ enum ChatNotify
CHAT_NOT_IN_LFG_NOTICE = 0x21, //+ "[%s] You must be queued in looking for group before joining this channel."; -- The user must be in the looking for group system to join LFG chat channels.
CHAT_VOICE_ON_NOTICE = 0x22, //+ "[%s] Channel voice enabled by %s.";
CHAT_VOICE_OFF_NOTICE = 0x23 //+ "[%s] Channel voice disabled by %s.";
// 0x24 enable voice?
// 0x24 enable voice?
};
class Channel
{
enum ChannelFlags
{
CHANNEL_FLAG_NONE = 0x00,
CHANNEL_FLAG_CUSTOM = 0x01,
// 0x02
CHANNEL_FLAG_TRADE = 0x04,
CHANNEL_FLAG_NOT_LFG = 0x08,
CHANNEL_FLAG_GENERAL = 0x10,
CHANNEL_FLAG_CITY = 0x20,
CHANNEL_FLAG_LFG = 0x40,
CHANNEL_FLAG_VOICE = 0x80
// General 0x18 = 0x10 | 0x08
// Trade 0x3C = 0x20 | 0x10 | 0x08 | 0x04
// LocalDefence 0x18 = 0x10 | 0x08
// GuildRecruitment 0x38 = 0x20 | 0x10 | 0x08
// LookingForGroup 0x50 = 0x40 | 0x10
};
enum ChannelFlags
{
CHANNEL_FLAG_NONE = 0x00,
CHANNEL_FLAG_CUSTOM = 0x01,
// 0x02
CHANNEL_FLAG_TRADE = 0x04,
CHANNEL_FLAG_NOT_LFG = 0x08,
CHANNEL_FLAG_GENERAL = 0x10,
CHANNEL_FLAG_CITY = 0x20,
CHANNEL_FLAG_LFG = 0x40,
CHANNEL_FLAG_VOICE = 0x80
// General 0x18 = 0x10 | 0x08
// Trade 0x3C = 0x20 | 0x10 | 0x08 | 0x04
// LocalDefence 0x18 = 0x10 | 0x08
// GuildRecruitment 0x38 = 0x20 | 0x10 | 0x08
// LookingForGroup 0x50 = 0x40 | 0x10
};
enum ChannelDBCFlags
{
CHANNEL_DBC_FLAG_NONE = 0x00000,
CHANNEL_DBC_FLAG_INITIAL = 0x00001, // General, Trade, LocalDefense, LFG
CHANNEL_DBC_FLAG_ZONE_DEP = 0x00002, // General, Trade, LocalDefense, GuildRecruitment
CHANNEL_DBC_FLAG_GLOBAL = 0x00004, // WorldDefense
CHANNEL_DBC_FLAG_TRADE = 0x00008, // Trade
CHANNEL_DBC_FLAG_CITY_ONLY = 0x00010, // Trade, GuildRecruitment
CHANNEL_DBC_FLAG_CITY_ONLY2 = 0x00020, // Trade, GuildRecruitment
CHANNEL_DBC_FLAG_DEFENSE = 0x10000, // LocalDefense, WorldDefense
CHANNEL_DBC_FLAG_GUILD_REQ = 0x20000, // GuildRecruitment
CHANNEL_DBC_FLAG_LFG = 0x40000 // LookingForGroup
};
enum ChannelDBCFlags
{
CHANNEL_DBC_FLAG_NONE = 0x00000,
CHANNEL_DBC_FLAG_INITIAL = 0x00001, // General, Trade, LocalDefense, LFG
CHANNEL_DBC_FLAG_ZONE_DEP = 0x00002, // General, Trade, LocalDefense, GuildRecruitment
CHANNEL_DBC_FLAG_GLOBAL = 0x00004, // WorldDefense
CHANNEL_DBC_FLAG_TRADE = 0x00008, // Trade
CHANNEL_DBC_FLAG_CITY_ONLY = 0x00010, // Trade, GuildRecruitment
CHANNEL_DBC_FLAG_CITY_ONLY2 = 0x00020, // Trade, GuildRecruitment
CHANNEL_DBC_FLAG_DEFENSE = 0x10000, // LocalDefense, WorldDefense
CHANNEL_DBC_FLAG_GUILD_REQ = 0x20000, // GuildRecruitment
CHANNEL_DBC_FLAG_LFG = 0x40000 // LookingForGroup
};
enum ChannelMemberFlags
{
MEMBER_FLAG_NONE = 0x00,
MEMBER_FLAG_OWNER = 0x01,
MEMBER_FLAG_MODERATOR = 0x02,
MEMBER_FLAG_VOICED = 0x04,
MEMBER_FLAG_MUTED = 0x08,
MEMBER_FLAG_CUSTOM = 0x10,
MEMBER_FLAG_MIC_MUTED = 0x20,
// 0x40
// 0x80
};
enum ChannelMemberFlags
{
MEMBER_FLAG_NONE = 0x00,
MEMBER_FLAG_OWNER = 0x01,
MEMBER_FLAG_MODERATOR = 0x02,
MEMBER_FLAG_VOICED = 0x04,
MEMBER_FLAG_MUTED = 0x08,
MEMBER_FLAG_CUSTOM = 0x10,
MEMBER_FLAG_MIC_MUTED = 0x20,
// 0x40
// 0x80
};
struct PlayerInfo
{
ObjectGuid player;
uint8 flags;
struct PlayerInfo
{
ObjectGuid player;
uint8 flags;
bool HasFlag(uint8 flag) { return flags & flag; }
void SetFlag(uint8 flag) { if (!HasFlag(flag)) flags |= flag; }
bool IsOwner() { return flags & MEMBER_FLAG_OWNER; }
void SetOwner(bool state)
{
if (state) flags |= MEMBER_FLAG_OWNER;
else flags &= ~MEMBER_FLAG_OWNER;
}
bool IsModerator() { return flags & MEMBER_FLAG_MODERATOR; }
void SetModerator(bool state)
{
if (state) flags |= MEMBER_FLAG_MODERATOR;
else flags &= ~MEMBER_FLAG_MODERATOR;
}
bool IsMuted() { return flags & MEMBER_FLAG_MUTED; }
void SetMuted(bool state)
{
if (state) flags |= MEMBER_FLAG_MUTED;
else flags &= ~MEMBER_FLAG_MUTED;
}
};
bool HasFlag(uint8 flag) { return flags & flag; }
void SetFlag(uint8 flag) { if (!HasFlag(flag)) flags |= flag; }
bool IsOwner() { return flags & MEMBER_FLAG_OWNER; }
void SetOwner(bool state)
{
if (state) flags |= MEMBER_FLAG_OWNER;
else flags &= ~MEMBER_FLAG_OWNER;
}
bool IsModerator() { return flags & MEMBER_FLAG_MODERATOR; }
void SetModerator(bool state)
{
if (state) flags |= MEMBER_FLAG_MODERATOR;
else flags &= ~MEMBER_FLAG_MODERATOR;
}
bool IsMuted() { return flags & MEMBER_FLAG_MUTED; }
void SetMuted(bool state)
{
if (state) flags |= MEMBER_FLAG_MUTED;
else flags &= ~MEMBER_FLAG_MUTED;
}
};
public:
Channel(const std::string& name, uint32 channel_id);
std::string GetName() const { return m_name; }
uint32 GetChannelId() const { return m_channelId; }
bool IsConstant() const { return m_channelId != 0; }
bool IsAnnounce() const { return m_announce; }
bool IsLFG() const { return GetFlags() & CHANNEL_FLAG_LFG; }
std::string GetPassword() const { return m_password; }
void SetPassword(const std::string& npassword) { m_password = npassword; }
void SetAnnounce(bool nannounce) { m_announce = nannounce; }
uint32 GetNumPlayers() const { return m_players.size(); }
uint8 GetFlags() const { return m_flags; }
bool HasFlag(uint8 flag) { return m_flags & flag; }
public:
Channel(const std::string& name, uint32 channel_id);
std::string GetName() const { return m_name; }
uint32 GetChannelId() const { return m_channelId; }
bool IsConstant() const { return m_channelId != 0; }
bool IsAnnounce() const { return m_announce; }
bool IsLFG() const { return GetFlags() & CHANNEL_FLAG_LFG; }
std::string GetPassword() const { return m_password; }
void SetPassword(const std::string& npassword) { m_password = npassword; }
void SetAnnounce(bool nannounce) { m_announce = nannounce; }
uint32 GetNumPlayers() const { return m_players.size(); }
uint8 GetFlags() const { return m_flags; }
bool HasFlag(uint8 flag) { return m_flags & flag; }
void Join(ObjectGuid p, const char* pass);
void Leave(ObjectGuid p, bool send = true);
void KickOrBan(ObjectGuid good, const char* badname, bool ban);
void Kick(ObjectGuid good, const char* badname) { KickOrBan(good, badname, false); }
void Ban(ObjectGuid good, const char* badname) { KickOrBan(good, badname, true); }
void UnBan(ObjectGuid good, const char* badname);
void Password(ObjectGuid p, const char* pass);
void SetMode(ObjectGuid p, const char* p2n, bool mod, bool set);
void SetOwner(ObjectGuid p, bool exclaim = true);
void SetOwner(ObjectGuid p, const char* newname);
void SendWhoOwner(ObjectGuid p);
void SetModerator(ObjectGuid p, const char* newname) { SetMode(p, newname, true, true); }
void UnsetModerator(ObjectGuid p, const char* newname) { SetMode(p, newname, true, false); }
void SetMute(ObjectGuid p, const char* newname) { SetMode(p, newname, false, true); }
void UnsetMute(ObjectGuid p, const char* newname) { SetMode(p, newname, false, false); }
void List(Player* p);
void Announce(ObjectGuid p);
void Moderate(ObjectGuid p);
void Say(ObjectGuid p, const char* what, uint32 lang);
void Invite(ObjectGuid p, const char* newp);
void Voice(ObjectGuid guid1, ObjectGuid guid2);
void DeVoice(ObjectGuid guid1, ObjectGuid guid2);
void JoinNotify(ObjectGuid guid); // invisible notify
void LeaveNotify(ObjectGuid guid); // invisible notify
void Join(Player* player, const char* password);
void Leave(Player* player, bool send = true);
void KickOrBan(Player* player, const char* targetName, bool ban);
void Kick(Player* player, const char* targetName) { KickOrBan(player, targetName, false); }
void Ban(Player* player, const char* targetName) { KickOrBan(player, targetName, true); }
void UnBan(Player* player, const char* targetName);
void Password(Player* player, const char* password);
void SetMode(Player* player, const char* targetName, bool moderator, bool set);
void SetOwner(ObjectGuid guid, bool exclaim = true);
void SetOwner(Player* player, const char* targetName);
void SendWhoOwner(Player* player);
void SetModerator(Player* player, const char* targetName) { SetMode(player, targetName, true, true); }
void UnsetModerator(Player* player, const char* targetName) { SetMode(player, targetName, true, false); }
void SetMute(Player* player, const char* targetName) { SetMode(player, targetName, false, true); }
void UnsetMute(Player* player, const char* targetName) { SetMode(player, targetName, false, false); }
void List(Player* player);
void Announce(Player* player);
void Moderate(Player* player);
void Say(Player* player, const char* text, uint32 lang);
void Invite(Player* player, const char* targetName);
void Voice(ObjectGuid guid1, ObjectGuid guid2);
void DeVoice(ObjectGuid guid1, ObjectGuid guid2);
void JoinNotify(ObjectGuid guid); // invisible notify
void LeaveNotify(ObjectGuid guid); // invisible notify
private:
// initial packet data (notify type and channel name)
void MakeNotifyPacket(WorldPacket* data, uint8 notify_type);
// type specific packet data
void MakeJoined(WorldPacket* data, ObjectGuid guid); //+ 0x00
void MakeLeft(WorldPacket* data, ObjectGuid guid); //+ 0x01
void MakeYouJoined(WorldPacket* data); //+ 0x02
void MakeYouLeft(WorldPacket* data); //+ 0x03
void MakeWrongPassword(WorldPacket* data); //? 0x04
void MakeNotMember(WorldPacket* data); //? 0x05
void MakeNotModerator(WorldPacket* data); //? 0x06
void MakePasswordChanged(WorldPacket* data, ObjectGuid guid); //+ 0x07
void MakeOwnerChanged(WorldPacket* data, ObjectGuid guid); //? 0x08
void MakePlayerNotFound(WorldPacket* data, const std::string& name); //+ 0x09
void MakeNotOwner(WorldPacket* data); //? 0x0A
void MakeChannelOwner(WorldPacket* data); //? 0x0B
void MakeModeChange(WorldPacket* data, ObjectGuid guid, uint8 oldflags);//+ 0x0C
void MakeAnnouncementsOn(WorldPacket* data, ObjectGuid guid); //+ 0x0D
void MakeAnnouncementsOff(WorldPacket* data, ObjectGuid guid); //+ 0x0E
void MakeModerationOn(WorldPacket* data, ObjectGuid guid); //+ 0x0F
void MakeModerationOff(WorldPacket* data, ObjectGuid guid); //+ 0x10
void MakeMuted(WorldPacket* data); //? 0x11
void MakePlayerKicked(WorldPacket* data, ObjectGuid bad, ObjectGuid good);//? 0x12
void MakeBanned(WorldPacket* data); //? 0x13
void MakePlayerBanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good);//? 0x14
void MakePlayerUnbanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good);//? 0x15
void MakePlayerNotBanned(WorldPacket* data, ObjectGuid guid); //? 0x16
void MakePlayerAlreadyMember(WorldPacket* data, ObjectGuid guid); //+ 0x17
void MakeInvite(WorldPacket* data, ObjectGuid guid); //? 0x18
void MakeInviteWrongFaction(WorldPacket* data); //? 0x19
void MakeWrongFaction(WorldPacket* data); //? 0x1A
void MakeInvalidName(WorldPacket* data); //? 0x1B
void MakeNotModerated(WorldPacket* data); //? 0x1C
void MakePlayerInvited(WorldPacket* data, const std::string& name); //+ 0x1D
void MakePlayerInviteBanned(WorldPacket* data, ObjectGuid guid); //? 0x1E
void MakeThrottled(WorldPacket* data); //? 0x1F
void MakeNotInArea(WorldPacket* data); //? 0x20
void MakeNotInLfg(WorldPacket* data); //? 0x21
void MakeVoiceOn(WorldPacket* data, ObjectGuid guid); //+ 0x22
void MakeVoiceOff(WorldPacket* data, ObjectGuid guid); //+ 0x23
private:
// initial packet data (notify type and channel name)
void MakeNotifyPacket(WorldPacket* data, uint8 notify_type);
// type specific packet data
void MakeJoined(WorldPacket* data, ObjectGuid guid); //+ 0x00
void MakeLeft(WorldPacket* data, ObjectGuid guid); //+ 0x01
void MakeYouJoined(WorldPacket* data); //+ 0x02
void MakeYouLeft(WorldPacket* data); //+ 0x03
void MakeWrongPassword(WorldPacket* data); //? 0x04
void MakeNotMember(WorldPacket* data); //? 0x05
void MakeNotModerator(WorldPacket* data); //? 0x06
void MakePasswordChanged(WorldPacket* data, ObjectGuid guid); //+ 0x07
void MakeOwnerChanged(WorldPacket* data, ObjectGuid guid); //? 0x08
void MakePlayerNotFound(WorldPacket* data, const std::string& name); //+ 0x09
void MakeNotOwner(WorldPacket* data); //? 0x0A
void MakeChannelOwner(WorldPacket* data); //? 0x0B
void MakeModeChange(WorldPacket* data, ObjectGuid guid, uint8 oldflags);//+ 0x0C
void MakeAnnouncementsOn(WorldPacket* data, ObjectGuid guid); //+ 0x0D
void MakeAnnouncementsOff(WorldPacket* data, ObjectGuid guid); //+ 0x0E
void MakeModerationOn(WorldPacket* data, ObjectGuid guid); //+ 0x0F
void MakeModerationOff(WorldPacket* data, ObjectGuid guid); //+ 0x10
void MakeMuted(WorldPacket* data); //? 0x11
void MakePlayerKicked(WorldPacket* data, ObjectGuid target, ObjectGuid source);//? 0x12
void MakeBanned(WorldPacket* data); //? 0x13
void MakePlayerBanned(WorldPacket* data, ObjectGuid target, ObjectGuid source);//? 0x14
void MakePlayerUnbanned(WorldPacket* data, ObjectGuid target, ObjectGuid source);//? 0x15
void MakePlayerNotBanned(WorldPacket* data, const std::string& name); //? 0x16
void MakePlayerAlreadyMember(WorldPacket* data, ObjectGuid guid); //+ 0x17
void MakeInvite(WorldPacket* data, ObjectGuid guid); //? 0x18
void MakeInviteWrongFaction(WorldPacket* data); //? 0x19
void MakeWrongFaction(WorldPacket* data); //? 0x1A
void MakeInvalidName(WorldPacket* data); //? 0x1B
void MakeNotModerated(WorldPacket* data); //? 0x1C
void MakePlayerInvited(WorldPacket* data, const std::string& name); //+ 0x1D
void MakePlayerInviteBanned(WorldPacket* data, const std::string& name);//? 0x1E
void MakeThrottled(WorldPacket* data); //? 0x1F
void MakeNotInArea(WorldPacket* data); //? 0x20
void MakeNotInLfg(WorldPacket* data); //? 0x21
void MakeVoiceOn(WorldPacket* data, ObjectGuid guid); //+ 0x22
void MakeVoiceOff(WorldPacket* data, ObjectGuid guid); //+ 0x23
void SendToAll(WorldPacket* data, ObjectGuid p = ObjectGuid());
void SendToOne(WorldPacket* data, ObjectGuid who);
void SendToAll(WorldPacket* data, ObjectGuid guid = ObjectGuid());
void SendToOne(WorldPacket* data, ObjectGuid who);
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 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(); }
uint8 GetPlayerFlags(ObjectGuid p) const
{
PlayerList::const_iterator p_itr = m_players.find(p);
if (p_itr == m_players.end())
return 0;
uint8 GetPlayerFlags(ObjectGuid guid) const
{
PlayerList::const_iterator p_itr = m_players.find(guid);
if (p_itr == m_players.end())
return 0;
return p_itr->second.flags;
}
return p_itr->second.flags;
}
void SetModerator(ObjectGuid p, bool set)
{
if (m_players[p].IsModerator() != set)
{
uint8 oldFlag = GetPlayerFlags(p);
m_players[p].SetModerator(set);
void SetModerator(ObjectGuid guid, bool set)
{
if (m_players[guid].IsModerator() != set)
{
uint8 oldFlag = GetPlayerFlags(guid);
m_players[guid].SetModerator(set);
WorldPacket data;
MakeModeChange(&data, p, oldFlag);
SendToAll(&data);
}
}
WorldPacket data;
MakeModeChange(&data, guid, oldFlag);
SendToAll(&data);
}
}
void SetMute(ObjectGuid p, bool set)
{
if (m_players[p].IsMuted() != set)
{
uint8 oldFlag = GetPlayerFlags(p);
m_players[p].SetMuted(set);
void SetMute(ObjectGuid guid, bool set)
{
if (m_players[guid].IsMuted() != set)
{
uint8 oldFlag = GetPlayerFlags(guid);
m_players[guid].SetMuted(set);
WorldPacket data;
MakeModeChange(&data, p, oldFlag);
SendToAll(&data);
}
}
WorldPacket data;
MakeModeChange(&data, guid, oldFlag);
SendToAll(&data);
}
}
private:
bool m_announce;
bool m_moderate;
std::string m_name;
std::string m_password;
uint8 m_flags;
uint32 m_channelId;
ObjectGuid m_ownerGuid;
private:
bool m_announce;
bool m_moderate;
std::string m_name;
std::string m_password;
uint8 m_flags;
uint32 m_channelId;
ObjectGuid m_ownerGuid;
typedef std::map<ObjectGuid, PlayerInfo> PlayerList;
PlayerList m_players;
GuidSet m_banned;
typedef std::map<ObjectGuid, PlayerInfo> PlayerList;
PlayerList m_players;
GuidSet m_banned;
};
#endif

View file

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

View file

@ -536,7 +536,8 @@ ChatCommand* ChatHandler::getCommandTable()
{ "creature_ai_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAIScriptsCommand, "", NULL },
{ "creature_ai_summons", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAISummonsCommand, "", 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_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesCreatureCommand, "", NULL },
{ "creature_questrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestRelationsCommand, "", NULL },
@ -985,7 +986,7 @@ void ChatHandler::SendSysMessage(const char* str)
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);
}
@ -1000,10 +1001,11 @@ void ChatHandler::SendGlobalSysMessage(const char* str)
// need copy to prevent corruption by strtok call in LineFromMessage original string
char* buf = mangos_strdup(str);
char* pos = buf;
ObjectGuid guid = m_session ? m_session->GetPlayer()->GetObjectGuid() : ObjectGuid();
while (char* line = LineFromMessage(pos))
{
FillSystemMessageData(&data, line);
ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, line, LANG_UNIVERSAL, CHAT_TAG_NONE, guid);
sWorld.SendGlobalMessage(&data);
}
@ -2095,99 +2097,6 @@ bool ChatHandler::isValidChatMessage(const char* message)
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()
{
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*/,
ObjectGuid const& senderGuid /*= ObjectGuid()*/, char const* senderName /*= NULL*/,
ObjectGuid const& targetGuid /*= ObjectGuid()*/, char const* targetName /*= NULL*/,
char const* channelName /*= NULL*/)
ObjectGuid const& senderGuid /*= ObjectGuid()*/, char const* senderName /*= nullptr*/,
ObjectGuid const& targetGuid /*= ObjectGuid()*/, char const* targetName /*= nullptr*/,
char const* channelName /*= nullptr*/, uint32 achievementId /*= 0*/, const char* addonPrefix /*= nullptr*/)
{
bool isGM = chatTag & CHAT_TAG_GM;
bool isAchievement = false;
data.Initialize(isGM ? SMSG_GM_MESSAGECHAT : SMSG_MESSAGECHAT);
data << uint8(msgtype);
@ -3731,60 +3641,76 @@ void ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg msgtype, char const
switch (msgtype)
{
case CHAT_MSG_MONSTER_SAY:
case CHAT_MSG_MONSTER_PARTY:
case CHAT_MSG_MONSTER_YELL:
case CHAT_MSG_MONSTER_WHISPER:
case CHAT_MSG_RAID_BOSS_WHISPER:
case CHAT_MSG_RAID_BOSS_EMOTE:
case CHAT_MSG_MONSTER_EMOTE:
MANGOS_ASSERT(senderName);
data << uint32(strlen(senderName) + 1);
data << senderName;
data << ObjectGuid(targetGuid); // Unit Target
if (targetGuid && !targetGuid.IsPlayer() && !targetGuid.IsPet())
{
data << uint32(strlen(targetName) + 1); // target name length
data << targetName; // target name
}
MANGOS_ASSERT(message);
data << uint32(strlen(message) + 1);
data << message;
data << uint8(chatTag);
break;
case CHAT_MSG_BG_SYSTEM_NEUTRAL:
case CHAT_MSG_BG_SYSTEM_ALLIANCE:
case CHAT_MSG_BG_SYSTEM_HORDE:
data << ObjectGuid(targetGuid); // Unit Target
if (targetGuid && !targetGuid.IsPlayer())
{
MANGOS_ASSERT(targetName);
data << uint32(strlen(targetName) + 1); // target name length
data << targetName; // target name
}
MANGOS_ASSERT(message);
data << uint32(strlen(message) + 1);
data << message;
data << uint8(chatTag);
break;
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)
{
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:
case CHAT_MSG_WHISPER_FOREIGN:
MANGOS_ASSERT(senderName);
data << uint32(strlen(senderName) + 1);
data << senderName;
}
break;
data << ObjectGuid(targetGuid); // Unit Target
if (targetGuid && !targetGuid.IsPlayer() && !targetGuid.IsPet() && (msgtype != CHAT_MSG_WHISPER_FOREIGN))
{
data << uint32(strlen(targetName) + 1); // target name length
data << targetName; // target name
}
break;
case CHAT_MSG_BG_SYSTEM_NEUTRAL:
case CHAT_MSG_BG_SYSTEM_ALLIANCE:
case CHAT_MSG_BG_SYSTEM_HORDE:
data << ObjectGuid(targetGuid); // Unit Target
if (targetGuid && !targetGuid.IsPlayer())
{
MANGOS_ASSERT(targetName);
data << uint32(strlen(targetName) + 1); // target name length
data << targetName; // target name
}
break;
case CHAT_MSG_ACHIEVEMENT:
case CHAT_MSG_GUILD_ACHIEVEMENT:
data << ObjectGuid(targetGuid); // Unit Target
isAchievement = true;
break;
default:
if (isGM)
{
MANGOS_ASSERT(senderName);
data << uint32(strlen(senderName) + 1);
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;
}
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
}
}

View file

@ -71,12 +71,12 @@ enum ChatCommandSearchResult
enum PlayerChatTag
{
CHAT_TAG_NONE = 0,
CHAT_TAG_AFK = 1,
CHAT_TAG_DND = 2,
CHAT_TAG_GM = 3,
CHAT_TAG_COM = 4, // Commentator
CHAT_TAG_DEV = 5, // Developer
CHAT_TAG_NONE = 0x00,
CHAT_TAG_AFK = 0x01,
CHAT_TAG_DND = 0x02,
CHAT_TAG_GM = 0x04,
CHAT_TAG_COM = 0x08, // Commentator
CHAT_TAG_DEV = 0x10, // Developer
};
typedef uint32 ChatTagFlags;
@ -87,23 +87,6 @@ class ChatHandler
explicit ChatHandler(Player* player);
~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; }
// 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 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 uint32 achievementId : Required only for *ACHIEVEMENT
* \param const char* addonPrefix : Required only for *CHAT_MSG_ADDON
**/
static void BuildChatPacket(
WorldPacket& data, ChatMsg msgtype, char const* message, Language language = LANG_UNIVERSAL, ChatTagFlags chatTag = CHAT_TAG_NONE,
static 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& targetGuid = ObjectGuid(), char const* targetName = NULL,
char const* channelName = NULL);
char const* channelName = NULL, uint32 achievementId = 0, const char* addonPrefix = NULL);
protected:
explicit ChatHandler() : m_session(NULL) {} // for CLI subclass
@ -450,6 +434,7 @@ class ChatHandler
bool HandleReloadAreaTriggerTavernCommand(char* args);
bool HandleReloadAreaTriggerTeleportCommand(char* args);
bool HandleReloadBattleEventCommand(char* args);
bool HandleReloadCreaturesStatsCommand(char* args);
bool HandleReloadCommandCommand(char* args);
bool HandleReloadConditionsCommand(char* args);
bool HandleReloadCreatureQuestRelationsCommand(char* args);

View file

@ -286,7 +286,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data)
return;
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()));
break;
@ -364,7 +364,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_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);
} break;
case CHAT_MSG_RAID_LEADER:
@ -394,7 +394,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_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);
} break;
@ -416,7 +416,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data)
WorldPacket data;
// 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);
} break;
@ -437,7 +437,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data)
return;
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);
} break;
@ -458,7 +458,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data)
return;
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);
} break;
@ -478,7 +478,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data)
if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
if (Channel* chn = cMgr->GetChannel(channel, _player))
chn->Say(_player->GetObjectGuid(), msg.c_str(), lang);
chn->Say(_player, msg.c_str(), lang);
} break;
case CHAT_MSG_AFK:
@ -539,7 +539,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data)
void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recv_data)
{
uint32 type;
ChatMsg type;
switch (recv_data.GetOpcode())
{
@ -573,7 +573,7 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recv_data)
return;
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);
break;
}
@ -618,7 +618,9 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recv_data)
if (!receiver)
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;
}
// Messages sent to "RAID" while in a party will get delivered to "PARTY"
@ -635,7 +637,7 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recv_data)
break;
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()));
break;
}
@ -768,7 +770,7 @@ void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data)
return;
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);
}

View file

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

View file

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

View file

@ -45,6 +45,7 @@
#include "BattleGround/BattleGroundMgr.h"
#include "Weather.h"
#include "Calendar.h"
#include "Chat.h"
#ifdef ENABLE_ELUNA
#include "LuaEngine.h"
#endif /* ENABLE_ELUNA */
@ -1970,8 +1971,8 @@ uint32 Map::GenerateLocalLowGuid(HighGuid guidhigh)
*/
class StaticMonsterChatBuilder
{
public:
StaticMonsterChatBuilder(CreatureInfo const* cInfo, ChatMsg msgtype, int32 textId, uint32 language, Unit const* target, uint32 senderLowGuid = 0)
public:
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)
{
// 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;
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:
@ -1992,7 +1994,7 @@ class StaticMonsterChatBuilder
CreatureInfo const* i_cInfo;
ChatMsg i_msgtype;
int32 i_textId;
uint32 i_language;
Language i_language;
Unit const* i_target;
};
@ -2126,3 +2128,178 @@ bool Map::ContainsGameObjectModel(const GameObjectModel& mdl) const
{
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
bool GetReachableRandomPosition(Unit* unit, float& x, float& y, float& z, float radius);
bool GetReachableRandomPointOnGround(float& x, float& y, float& z, float radius);
bool GetRandomPointInTheAir(float& x, float& y, float& z, float radius);
bool GetRandomPointUnderWater(float& x, float& y, float& z, float radius, GridMapLiquidData& liquid_status);
bool GetReachableRandomPointOnGround(uint32 phaseMask, float& x, float& y, float& z, float radius);
bool GetRandomPointInTheAir(uint32 phaseMask, float& x, float& y, float& z, float radius);
bool GetRandomPointUnderWater(uint32 phaseMask, float& x, float& y, float& z, float radius, GridMapLiquidData& liquid_status);
private:
void LoadMapAndVMap(int gx, int gy);

View file

@ -1565,7 +1565,7 @@ void WorldSession::HandleRequestHotfix(WorldPacket& recv_data)
count = recv_data.ReadBits(23);
std::vector<ObjectGuid> guids;
guids.reserve(count);
guids.resize(count);
for (uint32 i = 0; i < count; ++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 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);
data << ObjectGuid(guid);
data << uint32(trainer_type);
data << uint32(ci->trainerId);
data << uint32(TrainerType);
data << uint32(ci->TrainerTemplateId);
size_t count_pos = data.wpos();
data << uint32(maxcount);
@ -243,9 +243,9 @@ void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle)
void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recv_data)
{
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);
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 << uint32(ci->CreatureTypeFlags); // flags
data << uint32(0); // unk
data << uint32(ci->type); // CreatureType.dbc
data << uint32(ci->family); // CreatureFamily.dbc
data << uint32(ci->CreatureType); // CreatureType.dbc
data << uint32(ci->Family); // CreatureFamily.dbc
data << uint32(ci->Rank); // Creature Rank (elite, boss, etc)
data << uint32(ci->KillCredit[0]); // 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)
data << uint32(ci->ModelId[i]);
data << float(ci->healthModifier); // health modifier
data << float(ci->powerModifier); // power modifier
data << float(ci->HealthMultiplier); // health modifier
data << float(ci->PowerMultiplier); // power modifier
data << uint8(ci->RacialLeader);
for (uint32 i = 0; i < 6; ++i)
data << uint32(ci->questItems[i]); // itemId[6], quest drop
data << uint32(ci->movementId); // CreatureMovementInfo.dbc
data << uint32(ci->QuestItems[i]); // itemId[6], quest drop
data << uint32(ci->MovementTemplateId); // CreatureMovementInfo.dbc
data << uint32(0); //unk
SendPacket(&data);
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)
{
if (!m_script->textId[i])
{ break; }
break;
emotes.push_back(uint32(m_script->textId[i]));
}

View file

@ -3384,7 +3384,7 @@ void Spell::cast(bool skipCheck)
// Hand of Reckoning
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 ;) )
}
// 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 45391: // Summon Demonic Vapor (SWP, Felmyst)
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 45976: // Open Portal (SWP, M'uru)
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 63018: // Searing Light (Ulduar, XT-002)
case 63024: // Gravity Bomb (Ulduar, XT-002)
case 63387: // Rapid Burst
case 63545: // Icicle (Ulduar, Hodir)
case 63795: // Psychosis (Ulduar, Yogg-Saron)
case 63820: // Summon Scrap Bot Trigger (Ulduar, Mimiron) use for Scrap Bots, hits npc 33856
case 64218: // Overcharge (VoA, Emalon)
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 64531: // Rapid Burst (h)
case 64543: // Melt Ice (Ulduar, Hodir)
case 64623: // Frost Bomb (Ulduar, Mimiron)
case 65121: // Searing Light (h) (Ulduar, XT-002)
case 65301: // Psychosis (Ulduar, Yogg-Saron)
case 65872: // Pursuing Spikes (ToCrusader, Anub'arak)

View file

@ -448,7 +448,7 @@ enum AuraType
SPELL_AURA_297 = 297,
SPELL_AURA_298 = 298,
SPELL_AURA_299 = 299,
SPELL_AURA_300 = 300,
SPELL_AURA_SHARE_DAMAGE_PCT = 300,
SPELL_AURA_HEAL_ABSORB = 301,
SPELL_AURA_302 = 302,
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
if (caster->GetTypeId() == TYPEID_PLAYER &&
triggerTarget->GetTypeId() == TYPEID_UNIT &&
((Creature*)triggerTarget)->GetCreatureInfo()->type == CREATURE_TYPE_GAS_CLOUD)
((Creature*)triggerTarget)->GetCreatureInfo()->CreatureType == CREATURE_TYPE_GAS_CLOUD)
{
Player* player = (Player*)caster;
Creature* creature = (Creature*)triggerTarget;
// missing lootid has been reported on startup - just return
if (!creature->GetCreatureInfo()->SkinLootId)
// missing Lootid has been reported on startup - just return
if (!creature->GetCreatureInfo()->SkinningLootId)
return;
player->AutoStoreLoot(creature, creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, true);
player->AutoStoreLoot(creature, creature->GetCreatureInfo()->SkinningLootId, LootTemplates_Skinning, true);
creature->ForcedDespawn();
}
@ -2378,9 +2378,14 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
case 54729: // Winged Steed of the Ebon Blade
Spell::SelectMountByAreaAndSkill(target, GetSpellProto(), 0, 0, 54726, 54727, 0);
return;
case 58600: // Restricted Flight Area
target->MonsterWhisper(LANG_NO_FLY_ZONE, target, true);
case 58600: // Restricted Flight Area
{
if (!target || target->GetTypeId() != TYPEID_PLAYER)
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 61190: // Twilight Shift (many targets)
target->RemoveAurasDueToSpell(57620);
@ -2936,18 +2941,18 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
return;
}
case 64398: // Summon Scrap Bot (Ulduar, Mimiron) - for Scrap Bots
case 64426: // Summon Scrap Bot (Ulduar, Mimiron) - for Assault Bots
case 64621: // Summon Fire Bot (Ulduar, Mimiron)
case 62483: // Stonebark's Essence Channel
case 62484: // Ironbranch's Essence Channel
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;
switch (GetId())
if (Unit* caster = GetCaster())
{
case 64398: triggerSpell = 63819; break;
case 64426: triggerSpell = 64427; break;
case 64621: triggerSpell = 64622; break;
if (m_removeMode == AURA_REMOVE_BY_EXPIRE)
caster->CastSpell(caster, 62467, true);
}
target->CastSpell(target, triggerSpell, false);
return;
}
case 68839: // Corrupt Soul
@ -4487,15 +4492,15 @@ void Aura::HandleModCharm(bool apply, bool Real)
if (caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK)
{
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
if (target->GetByteValue(UNIT_FIELD_BYTES_0, 1) == 0)
{
if (cinfo->unit_class == 0)
sLog.outErrorDb("Creature (Entry: %u) have unit_class = 0 but used in charmed spell, that will be result client crash.", cinfo->Entry);
if (cinfo->UnitClass == 0)
sLog.outErrorDb("Creature (Entry: %u) have UnitClass = 0 but used in charmed spell, that will be result client crash.", cinfo->Entry);
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);
}
@ -4533,10 +4538,10 @@ void Aura::HandleModCharm(bool apply, bool Real)
target->setFaction(cinfo->FactionAlliance);
// 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
// m_target->SetByteValue(UNIT_FIELD_BYTES_0, 1, cinfo->unit_class);
// m_target->SetByteValue(UNIT_FIELD_BYTES_0, 1, cinfo->UnitClass);
if (target->GetCharmInfo())
{ target->GetCharmInfo()->SetPetNumber(0, true); }
@ -4947,13 +4952,8 @@ void Aura::HandleAuraModRoot(bool apply, bool Real)
if (GetSpellSchoolMask(GetSpellProto()) & SPELL_SCHOOL_MASK_FROST)
{ target->ModifyAuraState(AURA_STATE_FROZEN, apply); }
target->addUnitState(UNIT_STAT_ROOT);
target->SetTargetGuid(ObjectGuid());
// Save last orientation
if (target->getVictim())
target->SetOrientation(target->GetAngle(target->getVictim()));
if (target->GetTypeId() == TYPEID_PLAYER)
{
target->SetRoot(true);
@ -4991,18 +4991,14 @@ void Aura::HandleAuraModRoot(bool apply, bool Real)
// Real remove called after current aura remove from lists, check if other similar auras active
if (target->HasAuraType(SPELL_AURA_MOD_ROOT))
{ return; }
{
return;
}
target->clearUnitState(UNIT_STAT_ROOT);
if (!target->hasUnitState(UNIT_STAT_STUNNED)) // 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);
}
if (!target->hasUnitState(UNIT_STAT_STUNNED) && (target->GetTypeId() == TYPEID_PLAYER)) // prevent allow move if have also stun effect
target->SetRoot(false);
}
}
@ -7027,7 +7023,7 @@ void Aura::HandleAuraEmpathy(bool apply, bool /*Real*/)
return;
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);
}
@ -8346,6 +8342,14 @@ void Aura::PeriodicDummyTick()
target->CastSpell(target, 63536, true, NULL, this);
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
{
if (GetHolder()->GetStackAmount() >= 10)
@ -8826,7 +8830,7 @@ void Aura::HandleAuraMirrorImage(bool apply, bool Real)
const CreatureModelInfo* minfo = sObjectMgr.GetCreatureModelInfo(pCreature->GetNativeDisplayId());
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, 3, 0);

View file

@ -1542,6 +1542,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
unitTarget->CastSpell(unitTarget, spell_id, true);
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
{
if (!unitTarget)
@ -2738,6 +2746,31 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
unitTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE);
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
{
if (!unitTarget)
@ -2747,6 +2780,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
unitTarget->CastSpell(unitTarget, 62279, true);
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
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
@ -2764,6 +2805,15 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
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
{
if (!unitTarget)
@ -2779,6 +2829,22 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
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 64425: // Summon Scrap Bot Trigger (Ulduar - Mimiron) for Assault 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));
return;
}
case 64402: // Rocket Strike
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 63681, true);
return;
}
case 64489: // Feral Rush
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
@ -2818,6 +2892,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
m_caster->CastSpell(m_caster, 64540, true);
return;
}
case 64623: // Frost Bomb
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 64627, true);
return;
}
case 64673: // Feral Rush (h)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
@ -2826,6 +2908,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
m_caster->CastSpell(unitTarget, 64674, true);
return;
}
case 64841: // Rapid Burst
{
if (!unitTarget)
return;
unitTarget->CastSpell(m_caster, 63382, false);
return;
}
case 64981: // Summon Random Vanquished Tentacle
{
uint32 spell_id = 0;
@ -2840,6 +2930,16 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
m_caster->CastSpell(m_caster, spell_id, true);
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
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->GetTypeId() != TYPEID_PLAYER)
@ -5279,7 +5379,7 @@ void Spell::EffectSummonType(SpellEffectEntry const* effect)
return;
// 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);
else
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->InitLevelupSpellsForLevel(); // none?
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
// set timer for unsummon
if (m_duration > 0)
@ -5538,7 +5638,7 @@ bool Spell::DoSummonGuardian(CreatureSummonPositions& list, SummonPropertiesEntr
// spawnCreature->SetName(""); // generated by client
spawnCreature->SetOwnerGuid(m_caster->GetObjectGuid());
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->SetCreatorGuid(m_caster->GetObjectGuid());
@ -7597,6 +7697,23 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
unitTarget->CastSpell(unitTarget, triggeredSpell[urand(0, 3)], true);
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
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
@ -7771,6 +7888,14 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
unitTarget->CastSpell(unitTarget, 45259, true);
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
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
@ -7855,7 +7980,7 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
}
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_1, 0);
@ -8643,6 +8768,28 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
unitTarget->CastSpell(m_caster, 64909, true);
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
{
if (!unitTarget)
@ -8685,18 +8832,6 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
unitTarget->RemoveAuraHolderFromStack(spellId, numStacks);
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
{
uint32 spellId = effect->CalculateSimpleValue();

View file

@ -1214,6 +1214,13 @@ SpellAuraProcResult Unit::HandleDummyAuraProc(Unit* pVictim, uint32 damage, Aura
basepoints[0] = damage * 15 / 100;
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;
}
@ -3111,6 +3118,12 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
(((Creature*)pVictim)->GetCreatureInfo()->MechanicImmuneMask & (1 << (MECHANIC_STUN - 1))) == 0)
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;
}
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);
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
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_PLAYER_COMMANDS, "PlayerCommands", false);
setConfig(CONFIG_BOOL_PLAYER_COMMANDS, "PlayerCommands", true);
if (int clientCacheId = sConfig.GetIntDefault("ClientCacheVersion", 0))
{
@ -1782,19 +1783,7 @@ namespace MaNGOS
while (char* line = lineFromMessage(pos))
{
WorldPacket* data = new WorldPacket();
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);
ChatHandler::BuildChatPacket(*data, CHAT_MSG_SYSTEM, line);
data_list.push_back(data);
}
}

View file

@ -217,6 +217,7 @@ enum eConfigUInt32Values
CONFIG_UINT32_GUID_RESERVE_SIZE_CREATURE,
CONFIG_UINT32_GUID_RESERVE_SIZE_GAMEOBJECT,
CONFIG_UINT32_MIN_LEVEL_FOR_RAID,
CONFIG_UINT32_CREATURE_RESPAWN_AGGRO_DELAY,
CONFIG_UINT32_RANDOM_BG_RESET_HOUR,
// Warden
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
# Default: 10
#
# PlayerCommands
# Should player chat be parsed for GM commands.
# Default: 1 (parse commands)
# 0 (ignore commands)
#
################################################################################
GameType = 1
@ -856,6 +861,7 @@ WaitAtStartupError = 10
PlayerCommands = 0
Motd = "Welcome to Mangos Three."
Raid.MinLevel = 10
PlayerCommands = 1
################################################################################
# PLAYER INTERACTION
@ -1008,6 +1014,7 @@ TalentsInspecting = 1
ThreatRadius = 100
Rate.Creature.Aggro = 1
CreatureRespawnAggroDelay = 5000
CreatureFamilyFleeAssistanceRadius = 30
CreatureFamilyAssistanceRadius = 10
CreatureFamilyAssistanceDelay = 1500

View file

@ -144,7 +144,7 @@ bool npc_escortAI::AssistPlayerInCombat(Unit* pWho)
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))
{
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.");
}
// disable npcflags
// disable NpcFlagss
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());

View file

@ -82,7 +82,7 @@ bool FollowerAI::AssistPlayerInCombat(Unit* pWho)
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))
{
return false;

View file

@ -92,7 +92,7 @@ struct npc_kitten : public CreatureScript
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->IsWithinDistInMap(pWho, INTERACTION_DISTANCE))

View file

@ -86,7 +86,7 @@ struct boss_moam : public CreatureScript
m_creature->SetMaxPower(POWER_MANA, m_creature->GetCreatureInfo()->MaxLevelMana);
#endif
#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
}

View file

@ -102,7 +102,7 @@ struct mob_lump : public CreatureScript
m_creature->DeleteThreatList();
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->SetStandState(UNIT_STAND_STATE_SIT);

View file

@ -1213,9 +1213,9 @@ struct npc_guardian : public CreatureScript
# 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?
// (remember gossipHello is not called unless npcflag|1 is present)
// (remember gossipHello is not called unless NpcFlags|1 is present)
enum
{

View file

@ -41,18 +41,6 @@ BarGoLink::BarGoLink(int 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()
{
if (!m_showOutput)

View file

@ -40,8 +40,6 @@ class BarGoLink
* @param 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
*