[Core] Removed duplicate files

This commit is contained in:
Antz 2015-02-04 12:41:23 +00:00 committed by Antz
parent 70eb22792e
commit f230f1ae14
13 changed files with 24 additions and 56149 deletions

View file

@ -1,724 +0,0 @@
/*
* This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Calendar.h"
#include "Guild.h"
#include "Mail.h"
#include "ObjectMgr.h"
#include "ProgressBar.h"
INSTANTIATE_SINGLETON_1(CalendarMgr);
//////////////////////////////////////////////////////////////////////////
// CalendarEvent Class to store single event informations
//////////////////////////////////////////////////////////////////////////
CalendarEvent::~CalendarEvent()
{
RemoveAllInvite();
}
// Add an invite to internal invite map return true if success
bool CalendarEvent::AddInvite(CalendarInvite* invite)
{
if (!invite)
return false;
return m_Invitee.insert(CalendarInviteMap::value_type(invite->InviteId, invite)).second;
}
CalendarInvite* CalendarEvent::GetInviteById(uint64 inviteId)
{
CalendarInviteMap::iterator itr = m_Invitee.find(inviteId);
if (itr != m_Invitee.end())
return itr->second;
return NULL;
}
CalendarInvite* CalendarEvent::GetInviteByGuid(ObjectGuid const& guid)
{
CalendarInviteMap::const_iterator inviteItr = m_Invitee.begin();
while (inviteItr != m_Invitee.end())
{
if (inviteItr->second->InviteeGuid == guid)
return inviteItr->second;
++inviteItr;
}
return NULL;
}
// remove invite by its iterator
void CalendarEvent::RemoveInviteByItr(CalendarInviteMap::iterator inviteItr)
{
MANGOS_ASSERT(inviteItr != m_Invitee.end()); // iterator must be valid
if (!IsGuildEvent())
sCalendarMgr.SendCalendarEventInviteRemoveAlert(sObjectMgr.GetPlayer(inviteItr->second->InviteeGuid), this, CALENDAR_STATUS_REMOVED);
sCalendarMgr.SendCalendarEventInviteRemove(inviteItr->second, Flags);
CharacterDatabase.PExecute("DELETE FROM calendar_invites WHERE inviteId=" UI64FMTD, inviteItr->second->InviteId);
delete inviteItr->second;
m_Invitee.erase(inviteItr);
}
// remove invite by ObjectGuid of the player (may not be found so nothing removed)
void CalendarEvent::RemoveInviteByGuid(ObjectGuid const& playerGuid)
{
CalendarInviteMap::iterator itr = m_Invitee.begin();
while (itr != m_Invitee.end())
{
if (itr->second->InviteeGuid == playerGuid)
RemoveInviteByItr(itr++);
else
++itr;
}
}
// remove invite by invite ID (some check done before and if requirement not complete
// operation is aborted and raison is sent to client
bool CalendarEvent::RemoveInviteById(uint64 inviteId, Player* remover)
{
CalendarInviteMap::iterator inviteItr = m_Invitee.find(inviteId);
if (inviteItr == m_Invitee.end())
{
// invite not found
sCalendarMgr.SendCalendarCommandResult(remover, CALENDAR_ERROR_NO_INVITE);
return false;
}
// assign a pointer to CalendarInvite class to make read more easy
CalendarInvite* invite = inviteItr->second;
if (invite->InviteeGuid != remover->GetObjectGuid())
{
// check if remover is an invitee
CalendarInvite* removerInvite = GetInviteByGuid(remover->GetObjectGuid());
if (removerInvite == NULL)
{
// remover is not invitee cheat???
sCalendarMgr.SendCalendarCommandResult(remover, CALENDAR_ERROR_NOT_INVITED);
return false;
}
if (removerInvite->Rank != CALENDAR_RANK_MODERATOR && removerInvite->Rank != CALENDAR_RANK_OWNER)
{
// remover have not enough right to remove invite
sCalendarMgr.SendCalendarCommandResult(remover, CALENDAR_ERROR_PERMISSIONS);
return false;
}
}
if (CreatorGuid == invite->InviteeGuid)
{
sCalendarMgr.SendCalendarCommandResult(remover, CALENDAR_ERROR_DELETE_CREATOR_FAILED);
return false;
}
// TODO: Send mail to invitee if needed
RemoveInviteByItr(inviteItr);
return true;
}
// remove all invite without sending ingame mail
void CalendarEvent::RemoveAllInvite()
{
CalendarInviteMap::iterator itr = m_Invitee.begin();
while (itr != m_Invitee.end())
RemoveInviteByItr(itr++);
}
// remove all invite sending ingame mail
void CalendarEvent::RemoveAllInvite(ObjectGuid const& removerGuid)
{
// build mail title
std::ostringstream title;
title << removerGuid << ':' << Title;
// build mail body
std::ostringstream body;
body << secsToTimeBitFields(time(NULL));
// creating mail draft
MailDraft draft(title.str(), body.str());
CalendarInviteMap::iterator itr = m_Invitee.begin();
while (itr != m_Invitee.end())
{
if (removerGuid != itr->second->InviteeGuid)
draft.SendMailTo(MailReceiver(itr->second->InviteeGuid), this, MAIL_CHECK_MASK_COPIED);
RemoveInviteByItr(itr++);
}
}
//////////////////////////////////////////////////////////////////////////
// CalendarInvite Classes store single invite information
//////////////////////////////////////////////////////////////////////////
CalendarInvite::CalendarInvite(CalendarEvent* event, uint64 inviteId, ObjectGuid senderGuid, ObjectGuid inviteeGuid, time_t statusTime, CalendarInviteStatus status, CalendarModerationRank rank, std::string text) :
m_calendarEvent(event), InviteId(inviteId), SenderGuid(senderGuid), InviteeGuid(inviteeGuid), LastUpdateTime(statusTime), Status(status), Rank(rank), Text(text)
{
// only for pre invite case
if (!event)
InviteId = 0;
}
//////////////////////////////////////////////////////////////////////////
// CalendarMgr Classes handle all events and invites.
//////////////////////////////////////////////////////////////////////////
// fill all player events in provided CalendarEventsList
void CalendarMgr::GetPlayerEventsList(ObjectGuid const& guid, CalendarEventsList& calEventList)
{
uint32 guildId = 0;
Player* player = sObjectMgr.GetPlayer(guid);
if (player)
guildId = player->GetGuildId();
else
guildId = Player::GetGuildIdFromDB(guid);
for (CalendarEventStore::iterator itr = m_EventStore.begin(); itr != m_EventStore.end(); ++itr)
{
CalendarEvent* event = &itr->second;
// add own event and same guild event or announcement
if ((event->CreatorGuid == guid) || ((event->IsGuildAnnouncement() || event->IsGuildEvent()) && event->GuildId == guildId))
{
calEventList.push_back(event);
continue;
}
// add all event where player is invited
if (event->GetInviteByGuid(guid))
calEventList.push_back(event);
}
}
// fill all player invites in provided CalendarInvitesList
void CalendarMgr::GetPlayerInvitesList(ObjectGuid const& guid, CalendarInvitesList& calInvList)
{
for (CalendarEventStore::iterator itr = m_EventStore.begin(); itr != m_EventStore.end(); ++itr)
{
CalendarEvent* event = &itr->second;
if (event->IsGuildAnnouncement())
continue;
CalendarInviteMap const* cInvMap = event->GetInviteMap();
CalendarInviteMap::const_iterator ci_itr = cInvMap->begin();
while (ci_itr != cInvMap->end())
{
if (ci_itr->second->InviteeGuid == guid)
{
calInvList.push_back(ci_itr->second);
break;
}
++ci_itr;
}
}
}
// add single event to main events store
// some check done before so it may fail and raison is sent to client
// return value is the CalendarEvent pointer on success
CalendarEvent* CalendarMgr::AddEvent(ObjectGuid const& guid, std::string title, std::string description, uint32 type, uint32 repeatable,
uint32 maxInvites, int32 dungeonId, time_t eventTime, time_t unkTime, uint32 flags)
{
Player* player = sObjectMgr.GetPlayer(guid);
if (!player)
return NULL;
if (title.empty())
{
SendCalendarCommandResult(player, CALENDAR_ERROR_NEEDS_TITLE);
return NULL;
}
if (eventTime < time(NULL))
{
SendCalendarCommandResult(player, CALENDAR_ERROR_INVALID_DATE);
return NULL;
}
uint32 guildId = 0;
if ((flags & CALENDAR_FLAG_GUILD_EVENT) || (flags & CALENDAR_FLAG_GUILD_ANNOUNCEMENT))
{
guildId = player->GetGuildId();
if (!guildId)
{
SendCalendarCommandResult(player, CALENDAR_ERROR_GUILD_PLAYER_NOT_IN_GUILD);
return NULL;
}
if (!CanAddGuildEvent(guildId))
{
SendCalendarCommandResult(player, CALENDAR_ERROR_GUILD_EVENTS_EXCEEDED);
return NULL;
}
}
else
{
if (!CanAddEvent(guid))
{
SendCalendarCommandResult(player, CALENDAR_ERROR_EVENTS_EXCEEDED);
return NULL;
}
}
uint64 nId = GetNewEventId();
DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "CalendarMgr::AddEvent> ID(" UI64FMTD "), '%s', Desc > '%s', type=%u, repeat=%u, maxInvites=%u, dungeonId=%d, flags=%u",
nId, title.c_str(), description.c_str(), type, repeatable, maxInvites, dungeonId, flags);
CalendarEvent& newEvent = m_EventStore[nId];
newEvent.EventId = nId;
newEvent.CreatorGuid = guid;
newEvent.Title = title;
newEvent.Description = description;
newEvent.Type = (CalendarEventType) type;
newEvent.Repeatable = (CalendarRepeatType) repeatable;
newEvent.DungeonId = dungeonId;
newEvent.EventTime = eventTime;
newEvent.Flags = flags;
newEvent.GuildId = guildId;
CharacterDatabase.escape_string(title);
CharacterDatabase.escape_string(description);
CharacterDatabase.PExecute("INSERT INTO calendar_events VALUES (" UI64FMTD ", %u, %u, %u, %u, %d, %u, '%s', '%s')",
nId,
guid.GetCounter(),
guildId,
type,
flags,
dungeonId,
uint32(eventTime),
title.c_str(),
description.c_str());
return &newEvent;
}
// remove event by its id
// some check done before so it may fail and raison is sent to client
void CalendarMgr::RemoveEvent(uint64 eventId, Player* remover)
{
CalendarEventStore::iterator citr = m_EventStore.find(eventId);
if (citr == m_EventStore.end())
{
SendCalendarCommandResult(remover, CALENDAR_ERROR_EVENT_INVALID);
return;
}
if (remover->GetObjectGuid() != citr->second.CreatorGuid)
{
// only creator can remove his event
SendCalendarCommandResult(remover, CALENDAR_ERROR_PERMISSIONS);
return;
}
SendCalendarEventRemovedAlert(&citr->second);
CharacterDatabase.PExecute("DELETE FROM calendar_events WHERE eventId=" UI64FMTD, eventId);
// explicitly remove all invite and send mail to all invitee
citr->second.RemoveAllInvite(remover->GetObjectGuid());
m_EventStore.erase(citr);
}
// Add invit to an event and inform client
// some check done before so it may fail and raison is sent to client
// return value is the CalendarInvite pointer on success
CalendarInvite* CalendarMgr::AddInvite(CalendarEvent* event, ObjectGuid const& senderGuid, ObjectGuid const& inviteeGuid, CalendarInviteStatus status, CalendarModerationRank rank, std::string text, time_t statusTime)
{
Player* sender = sObjectMgr.GetPlayer(senderGuid);
if (!event || !sender)
return NULL;
std::string name;
sObjectMgr.GetPlayerNameByGUID(inviteeGuid, name);
// check if invitee is not already invited
if (event->GetInviteByGuid(inviteeGuid))
{
SendCalendarCommandResult(sender, CALENDAR_ERROR_ALREADY_INVITED_TO_EVENT_S, name.c_str());
return NULL;
}
// check if player can still have new invite (except for event creator)
if (!event->IsGuildAnnouncement() && event->CreatorGuid != inviteeGuid)
{
if (!CanAddInviteTo(inviteeGuid))
{
SendCalendarCommandResult(sender, CALENDAR_ERROR_OTHER_INVITES_EXCEEDED_S, name.c_str());
return NULL;
}
}
CalendarInvite* invite = new CalendarInvite(event, GetNewInviteId(), senderGuid, inviteeGuid, statusTime, status, rank, text);
if (!event->IsGuildAnnouncement())
SendCalendarEventInvite(invite);
if (!event->IsGuildEvent() || invite->InviteeGuid == event->CreatorGuid)
SendCalendarEventInviteAlert(invite);
if (event->IsGuildAnnouncement())
{
// no need to realy add invite for announcements
delete invite;
return NULL;
}
DEBUG_FILTER_LOG(LOG_FILTER_CALENDAR, "Add Invite> eventId[" UI64FMTD "], senderGuid[%s], inviteGuid[%s], Status[%u], rank[%u], text[%s], time[%u]",
event->EventId, senderGuid.GetString().c_str(), inviteeGuid.GetString().c_str(), uint32(status), uint32(rank), text.c_str(), uint32(statusTime));
if (!event->AddInvite(invite))
{
sLog.outError("CalendarEvent::AddInvite > Fail adding invite!");
delete invite;
return NULL;
}
CharacterDatabase.PExecute("INSERT INTO calendar_invites VALUES (" UI64FMTD ", " UI64FMTD ", %u, %u, %u, %u, %u)",
invite->InviteId,
event->EventId,
inviteeGuid.GetCounter(),
senderGuid.GetCounter(),
uint32(status),
uint32(statusTime),
uint32(rank));
return invite;
}
// remove invit from an event and inform client
// some check done before so it may fail and raison is sent to client
// require valid eventId/inviteId and correct right for the remover.
bool CalendarMgr::RemoveInvite(uint64 eventId, uint64 inviteId, ObjectGuid const& removerGuid)
{
Player* remover = sObjectMgr.GetPlayer(removerGuid);
CalendarEventStore::iterator citr = m_EventStore.find(eventId);
if (citr == m_EventStore.end())
{
SendCalendarCommandResult(remover, CALENDAR_ERROR_EVENT_INVALID);
return false;
}
CalendarEvent& event = citr->second;
return event.RemoveInviteById(inviteId, remover);
}
// return how many events still require some pending action
uint32 CalendarMgr::GetPlayerNumPending(ObjectGuid const& guid)
{
CalendarInvitesList inviteList;
GetPlayerInvitesList(guid, inviteList);
uint32 pendingNum = 0;
time_t currTime = time(NULL);
for (CalendarInvitesList::const_iterator itr = inviteList.begin(); itr != inviteList.end(); ++itr)
{
if (CalendarEvent const* event = (*itr)->GetCalendarEvent())
{
// pass all passed events
if (event->EventTime < currTime)
continue;
// pass all locked events
if (event->Flags & CALENDAR_FLAG_INVITES_LOCKED)
continue;
}
// add only invite that require some action
if ((*itr)->Status == CALENDAR_STATUS_INVITED || (*itr)->Status == CALENDAR_STATUS_TENTATIVE || (*itr)->Status == CALENDAR_STATUS_NOT_SIGNED_UP)
++pendingNum;
}
return pendingNum;
}
// copy event to another date (all invitee is copied too but their status are reseted)
void CalendarMgr::CopyEvent(uint64 eventId, time_t newTime, ObjectGuid const& guid)
{
Player* player = sObjectMgr.GetPlayer(guid);
CalendarEvent* event = GetEventById(eventId);
if (!event)
{
SendCalendarCommandResult(player, CALENDAR_ERROR_EVENT_INVALID);
return;
}
CalendarEvent* newEvent = AddEvent(guid, event->Title, event->Description, event->Type, event->Repeatable,
CALENDAR_MAX_INVITES, event->DungeonId, newTime, event->UnknownTime, event->Flags);
if (!newEvent)
return;
if (newEvent->IsGuildAnnouncement())
AddInvite(newEvent, guid, guid, CALENDAR_STATUS_CONFIRMED, CALENDAR_RANK_OWNER, "", time(NULL));
else
{
// copy all invitees, set new owner as the one who make the copy, set invitees status to invited
CalendarInviteMap const* cInvMap = event->GetInviteMap();
CalendarInviteMap::const_iterator ci_itr = cInvMap->begin();
while (ci_itr != cInvMap->end())
{
if (ci_itr->second->InviteeGuid == guid)
{
AddInvite(newEvent, guid, ci_itr->second->InviteeGuid, CALENDAR_STATUS_CONFIRMED, CALENDAR_RANK_OWNER, "", time(NULL));
}
else
{
CalendarModerationRank rank = CALENDAR_RANK_PLAYER;
// copy moderator rank
if (ci_itr->second->Rank == CALENDAR_RANK_MODERATOR)
rank = CALENDAR_RANK_MODERATOR;
AddInvite(newEvent, guid, ci_itr->second->InviteeGuid, CALENDAR_STATUS_INVITED, rank, "", time(NULL));
}
++ci_itr;
}
}
SendCalendarEvent(player, newEvent, CALENDAR_SENDTYPE_COPY);
}
// remove all events and invite of player
// used when player is deleted
void CalendarMgr::RemovePlayerCalendar(ObjectGuid const& playerGuid)
{
CalendarEventStore::iterator itr = m_EventStore.begin();
while (itr != m_EventStore.end())
{
if (itr->second.CreatorGuid == playerGuid)
{
// all invite will be automaticaly deleted
m_EventStore.erase(itr++);
// itr already incremented so go recheck event owner
continue;
}
// event not owned by playerGuid but an invite can still be found
CalendarEvent* event = &itr->second;
event->RemoveInviteByGuid(playerGuid);
++itr;
}
}
// remove all events and invite of player related to a specific guild
// used when player quit a guild
void CalendarMgr::RemoveGuildCalendar(ObjectGuid const& playerGuid, uint32 GuildId)
{
CalendarEventStore::iterator itr = m_EventStore.begin();
while (itr != m_EventStore.end())
{
CalendarEvent* event = &itr->second;
if (event->CreatorGuid == playerGuid && (event->IsGuildEvent() || event->IsGuildAnnouncement()))
{
// all invite will be automaticaly deleted
m_EventStore.erase(itr++);
// itr already incremented so go recheck event owner
continue;
}
// event not owned by playerGuid but an guild invite can still be found
if (event->GuildId != GuildId || !(event->IsGuildEvent() || event->IsGuildAnnouncement()))
{
++itr;
continue;
}
event->RemoveInviteByGuid(playerGuid);
++itr;
}
}
// load all events and their related invites from invite
void CalendarMgr::LoadCalendarsFromDB()
{
// in case of reload (not yet implemented)
m_MaxInviteId = 0;
m_MaxEventId = 0;
m_EventStore.clear();
sLog.outString("Loading Calendar Events...");
// 0 1 2 3 4 5 6 7 8
QueryResult* eventsQuery = CharacterDatabase.Query("SELECT eventId, creatorGuid, guildId, type, flags, dungeonId, eventTime, title, description FROM calendar_events ORDER BY eventId");
if (!eventsQuery)
{
BarGoLink bar(1);
bar.step();
sLog.outString();
sLog.outString(">> calendar_events table is empty!");
}
else
{
BarGoLink bar(eventsQuery->GetRowCount());
do
{
Field* field = eventsQuery->Fetch();
bar.step();
uint64 eventId = field[0].GetUInt64();
CalendarEvent& newEvent = m_EventStore[eventId];
newEvent.EventId = eventId;
newEvent.CreatorGuid = ObjectGuid(HIGHGUID_PLAYER, field[1].GetUInt32());
newEvent.GuildId = field[2].GetUInt32();
newEvent.Type = CalendarEventType(field[3].GetUInt8());
newEvent.Flags = field[4].GetUInt32();
newEvent.DungeonId = field[5].GetInt32();
newEvent.EventTime = time_t(field[6].GetUInt32());
newEvent.Title = field[7].GetCppString();
newEvent.Description = field[8].GetCppString();
m_MaxEventId = std::max(eventId, m_MaxEventId);
}
while (eventsQuery->NextRow());
sLog.outString();
sLog.outString(">> Loaded %u events!", uint32(eventsQuery->GetRowCount()));
delete eventsQuery;
}
sLog.outString("Loading Calendar invites...");
// 0 1 2 3 4 5 6
QueryResult* invitesQuery = CharacterDatabase.Query("SELECT inviteId, eventId, inviteeGuid, senderGuid, status, lastUpdateTime, rank FROM calendar_invites ORDER BY inviteId");
if (!invitesQuery)
{
BarGoLink bar(1);
bar.step();
sLog.outString();
if (m_MaxEventId) // An Event was loaded before
{
// delete all events (no event exist without at least one invite)
m_EventStore.clear();
m_MaxEventId = 0;
CharacterDatabase.DirectExecute("TRUNCATE TABLE calendar_events");
sLog.outString(">> calendar_invites table is empty, cleared calendar_events table!");
}
else
sLog.outString(">> calendar_invite table is empty!");
}
else
{
if (m_MaxEventId)
{
uint64 totalInvites = 0;
uint32 deletedInvites = 0;
BarGoLink bar(invitesQuery->GetRowCount());
do
{
Field* field = invitesQuery->Fetch();
uint64 inviteId = field[0].GetUInt64();
uint64 eventId = field[1].GetUInt64();
ObjectGuid inviteeGuid = ObjectGuid(HIGHGUID_PLAYER, field[2].GetUInt32());
ObjectGuid senderGuid = ObjectGuid(HIGHGUID_PLAYER, field[3].GetUInt32());
CalendarInviteStatus status = CalendarInviteStatus(field[4].GetUInt8());
time_t lastUpdateTime = time_t(field[5].GetUInt32());
CalendarModerationRank rank = CalendarModerationRank(field[6].GetUInt8());
CalendarEvent* event = GetEventById(eventId);
if (!event)
{
// delete invite
CharacterDatabase.PExecute("DELETE FROM calendar_invites WHERE inviteId =" UI64FMTD, field[0].GetUInt64());
++deletedInvites;
continue;
}
CalendarInvite* invite = new CalendarInvite(event, inviteId, senderGuid, inviteeGuid, lastUpdateTime, status, rank, "");
event->AddInvite(invite);
++totalInvites;
m_MaxInviteId = std::max(inviteId, m_MaxInviteId);
}
while (invitesQuery->NextRow());
sLog.outString();
sLog.outString(">> Loaded " UI64FMTD " invites! %s", totalInvites, (deletedInvites != 0) ? "(deleted some invites without corresponding event!)" : "");
}
else
{
// delete all invites (no invites exist without events)
CharacterDatabase.DirectExecute("TRUNCATE TABLE calendar_invites");
sLog.outString(">> calendar_invites table is cleared! (invites without events found)");
}
delete invitesQuery;
}
sLog.outString();
}
// check if player have not reached event limit
bool CalendarMgr::CanAddEvent(ObjectGuid const& guid)
{
uint32 totalEvents = 0;
// count all event created by guid
for (CalendarEventStore::iterator itr = m_EventStore.begin(); itr != m_EventStore.end(); ++itr)
if ((itr->second.CreatorGuid == guid) && (++totalEvents >= CALENDAR_MAX_EVENTS))
return false;
return true;
}
// check if guild have not reached event limit
bool CalendarMgr::CanAddGuildEvent(uint32 guildId)
{
if (!guildId)
return false;
uint32 totalEvents = 0;
// count all guild events in a guild
for (CalendarEventStore::iterator itr = m_EventStore.begin(); itr != m_EventStore.end(); ++itr)
if ((itr->second.GuildId == guildId) && (++totalEvents >= CALENDAR_MAX_GUILD_EVENTS))
return false;
return true;
}
// check if an invitee have not reached invite limit
bool CalendarMgr::CanAddInviteTo(ObjectGuid const& guid)
{
uint32 totalInvites = 0;
for (CalendarEventStore::iterator itr = m_EventStore.begin(); itr != m_EventStore.end(); ++itr)
{
CalendarEvent* event = &itr->second;
if (event->IsGuildAnnouncement())
continue;
CalendarInviteMap const* cInvMap = event->GetInviteMap();
CalendarInviteMap::const_iterator ci_itr = cInvMap->begin();
while (ci_itr != cInvMap->end())
{
if ((ci_itr->second->InviteeGuid == guid) && (++totalInvites >= CALENDAR_MAX_INVITES))
return false;
++ci_itr;
}
}
return true;
}

File diff suppressed because it is too large Load diff

View file

@ -1,875 +0,0 @@
/**
* This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* @addtogroup mailing
* @{
*
* @file MailHandler.cpp
* This file contains handlers for mail opcodes.
*
*/
#include "Mail.h"
#include "Language.h"
#include "Log.h"
#include "ObjectGuid.h"
#include "ObjectMgr.h"
#include "Item.h"
#include "Player.h"
#include "World.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "Opcodes.h"
#include "Chat.h"
bool WorldSession::CheckMailBox(ObjectGuid guid)
{
// GM case
if (guid == GetPlayer()->GetObjectGuid())
{
// command case will return only if player have real access to command
if (!ChatHandler(GetPlayer()).FindCommand("mailbox"))
{
DEBUG_LOG("%s attempt open mailbox in cheating way.", guid.GetString().c_str());
return false;
}
}
// mailbox case
else if (guid.IsGameObject())
{
if (!GetPlayer()->GetGameObjectIfCanInteractWith(guid, GAMEOBJECT_TYPE_MAILBOX))
{
DEBUG_LOG("Mailbox %s not found or %s can't interact with him.", guid.GetString().c_str(), GetPlayer()->GetGuidStr().c_str());
return false;
}
}
// squire case
else if (guid.IsAnyTypeCreature())
{
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
if (!creature)
{
DEBUG_LOG("%s not found or %s can't interact with him.", creature->GetGuidStr().c_str(), GetPlayer()->GetGuidStr().c_str());
return false;
}
if (!(creature->GetCreatureInfo()->type_flags & CREATURE_TYPEFLAGS_SQUIRE))
{
DEBUG_LOG("%s not have access to mailbox.", creature->GetGuidStr().c_str());
return false;
}
if (creature->GetOwnerGuid() != GetPlayer()->GetObjectGuid())
{
DEBUG_LOG("%s not owned by %s for access to mailbox.", creature->GetGuidStr().c_str(), GetPlayer()->GetGuidStr().c_str());
return false;
}
}
else
return false;
return true;
}
/*
* Handles the Packet sent by the client when sending a mail.
*
* This methods takes the packet sent by the client and performs the following actions:
* - Checks whether the mail is valid: i.e. can he send the selected items,
* does he have enough money, etc.
* - Creates a MailDraft and adds the needed items, money, cost data.
* - Sends the mail.
*
* Depending on the outcome of the checks performed the player will recieve a different
* MailResponseResult.
*
* @see MailResponseResult
* @see SendMailResult()
*
* @param recv_data the WorldPacket containing the data sent by the client.
*/
void WorldSession::HandleSendMail(WorldPacket& recv_data)
{
sLog.outError("WORLD: CMSG_SEND_MAIL");
ObjectGuid mailboxGuid;
uint64 money, COD;
std::string receiver, subject, body;
uint8 receiverLen, subjectLen, bodyLen;
uint32 unk1, unk2;
recv_data >> unk1; // stationery?
recv_data >> unk2; // 0x00000000
recv_data >> COD >> money; // cod and money
bodyLen = recv_data.ReadBits(12);
subjectLen = recv_data.ReadBits(9);
uint8 items_count = recv_data.ReadBits(5); // attached items count
if (items_count > MAX_MAIL_ITEMS) // client limit
{
GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS);
recv_data.rfinish(); // set to end to avoid warnings spam
return;
}
recv_data.ReadGuidMask<0>(mailboxGuid);
ObjectGuid itemGuids[MAX_MAIL_ITEMS];
for (uint8 i = 0; i < items_count; ++i)
recv_data.ReadGuidMask<2, 6, 3, 7, 1, 0, 4, 5>(itemGuids[i]);
recv_data.ReadGuidMask<3, 4>(mailboxGuid);
receiverLen = recv_data.ReadBits(7);
recv_data.ReadGuidMask<2, 6, 1, 7, 5>(mailboxGuid);
recv_data.ReadGuidBytes<4>(mailboxGuid);
for (uint8 i = 0; i < items_count; ++i)
{
recv_data.ReadGuidBytes<6, 1, 7, 2>(itemGuids[i]);
recv_data.read_skip<uint8>(); // item slot in mail, not used
recv_data.ReadGuidBytes<3, 0, 4, 5>(itemGuids[i]);
}
recv_data.ReadGuidBytes<7, 3, 6, 5>(mailboxGuid);
subject = recv_data.ReadString(subjectLen);
receiver = recv_data.ReadString(receiverLen);
recv_data.ReadGuidBytes<2, 0>(mailboxGuid);
body = recv_data.ReadString(bodyLen);
recv_data.ReadGuidBytes<1>(mailboxGuid);
DEBUG_LOG("WORLD: CMSG_SEND_MAIL receiver '%s' subject '%s' body '%s' mailbox " UI64FMTD " money " UI64FMTD " COD " UI64FMTD " unkt1 %u unk2 %u",
receiver.c_str(), subject.c_str(), body.c_str(), mailboxGuid.GetRawValue(), money, COD, unk1, unk2);
// packet read complete, now do check
if (!CheckMailBox(mailboxGuid))
return;
if (receiver.empty())
return;
Player* pl = _player;
ObjectGuid rc;
if (normalizePlayerName(receiver))
rc = sObjectMgr.GetPlayerGuidByName(receiver);
if (!rc)
{
DEBUG_LOG("%s is sending mail to %s (GUID: nonexistent!) with subject %s and body %s includes %u items, " UI64FMTD " copper and " UI64FMTD " COD copper with unk1 = %u, unk2 = %u",
pl->GetGuidStr().c_str(), receiver.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2);
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND);
return;
}
DEBUG_LOG("%s is sending mail to %s with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u",
pl->GetGuidStr().c_str(), rc.GetString().c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2);
if (pl->GetObjectGuid() == rc)
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF);
return;
}
uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client
uint64 reqmoney = cost + money;
if (pl->GetMoney() < reqmoney)
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY);
return;
}
Player* receive = sObjectMgr.GetPlayer(rc);
Team rc_team;
uint8 mails_count = 0; // do not allow to send to one player more than 100 mails
if (receive)
{
rc_team = receive->GetTeam();
mails_count = receive->GetMailSize();
}
else
{
rc_team = sObjectMgr.GetPlayerTeamByGUID(rc);
if (QueryResult* result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM mail WHERE receiver = '%u'", rc.GetCounter()))
{
Field* fields = result->Fetch();
mails_count = fields[0].GetUInt32();
delete result;
}
}
// do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255..
if (mails_count > 100)
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_CAP_REACHED);
return;
}
// check the receiver's Faction...
if (!sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_MAIL) && pl->GetTeam() != rc_team && GetSecurity() == SEC_PLAYER)
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM);
return;
}
uint32 rc_account = receive
? receive->GetSession()->GetAccountId()
: sObjectMgr.GetPlayerAccountIdByGUID(rc);
Item* items[MAX_MAIL_ITEMS];
for (uint8 i = 0; i < items_count; ++i)
{
if (!itemGuids[i].IsItem())
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID);
return;
}
Item* item = pl->GetItemByGuid(itemGuids[i]);
// prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail)
if (!item)
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID);
return;
}
if (!item->CanBeTraded(true))
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM);
return;
}
if (item->IsBoundAccountWide() && item->IsSoulBound() && pl->GetSession()->GetAccountId() != rc_account)
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS);
return;
}
if ((item->GetProto()->Flags & ITEM_FLAG_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION))
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM);
return;
}
if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED))
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD);
return;
}
items[i] = item;
}
pl->SendMailResult(0, MAIL_SEND, MAIL_OK);
pl->ModifyMoney(-int64(reqmoney));
pl->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost);
bool needItemDelay = false;
MailDraft draft(subject, body);
if (items_count > 0 || money > 0)
{
if (items_count > 0)
{
for (uint8 i = 0; i < items_count; ++i)
{
Item* item = items[i];
if (GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE))
{
sLog.outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)",
GetPlayerName(), GetAccountId(), item->GetProto()->Name1, item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account);
}
pl->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true);
CharacterDatabase.BeginTransaction();
item->DeleteFromInventoryDB(); // deletes item from character's inventory
item->SaveToDB(); // recursive and not have transaction guard into self, item not in inventory and can be save standalone
// owner in data will set at mail receive and item extracting
CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", rc.GetCounter(), item->GetGUIDLow());
CharacterDatabase.CommitTransaction();
draft.AddItem(item);
}
// if item send to character at another account, then apply item delivery delay
needItemDelay = pl->GetSession()->GetAccountId() != rc_account;
}
if (money > 0 && GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE))
{
sLog.outCommand(GetAccountId(), "GM %s (Account: %u) mail money: " UI64FMTD " to player: %s (Account: %u)",
GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account);
}
}
// If theres is an item, there is a one hour delivery delay if sent to another account's character.
uint32 deliver_delay = needItemDelay ? sWorld.getConfig(CONFIG_UINT32_MAIL_DELIVERY_DELAY) : 0;
// will delete item or place to receiver mail list
draft
.SetMoney(money)
.SetCOD(COD)
.SendMailTo(MailReceiver(receive, rc), pl, body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay);
CharacterDatabase.BeginTransaction();
pl->SaveInventoryAndGoldToDB();
CharacterDatabase.CommitTransaction();
}
/**
* Handles the Packet sent by the client when reading a mail.
*
* This method is called when a client reads a mail that was previously unread.
* It will add the MAIL_CHECK_MASK_READ flag to the mail being read.
*
* @see MailCheckMask
*
* @param recv_data the packet containing information about the mail the player read.
*
*/
void WorldSession::HandleMailMarkAsRead(WorldPacket& recv_data)
{
ObjectGuid mailboxGuid;
uint32 mailId;
recv_data >> mailboxGuid;
recv_data >> mailId;
if (!CheckMailBox(mailboxGuid))
return;
Player* pl = _player;
if (Mail* m = pl->GetMail(mailId))
{
if (pl->unReadMails)
--pl->unReadMails;
m->checked = m->checked | MAIL_CHECK_MASK_READ;
pl->m_mailsUpdated = true;
m->state = MAIL_STATE_CHANGED;
}
}
/**
* Handles the Packet sent by the client when deleting a mail.
*
* This method is called when a client deletes a mail in his mailbox.
*
* @param recv_data The packet containing information about the mail being deleted.
*
*/
void WorldSession::HandleMailDelete(WorldPacket& recv_data)
{
ObjectGuid mailboxGuid;
uint32 mailId;
recv_data >> mailboxGuid;
recv_data >> mailId;
recv_data.read_skip<uint32>(); // mailTemplateId
if (!CheckMailBox(mailboxGuid))
return;
Player* pl = _player;
pl->m_mailsUpdated = true;
if (Mail* m = pl->GetMail(mailId))
{
// delete shouldn't show up for COD mails
if (m->COD)
{
pl->SendMailResult(mailId, MAIL_DELETED, MAIL_ERR_INTERNAL_ERROR);
return;
}
m->state = MAIL_STATE_DELETED;
}
pl->SendMailResult(mailId, MAIL_DELETED, MAIL_OK);
}
/**
* Handles the Packet sent by the client when returning a mail to sender.
* This method is called when a player chooses to return a mail to its sender.
* It will create a new MailDraft and add the items, money, etc. associated with the mail
* and then send the mail to the original sender.
*
* @param recv_data The packet containing information about the mail being returned.
*
*/
void WorldSession::HandleMailReturnToSender(WorldPacket& recv_data)
{
ObjectGuid mailboxGuid;
uint32 mailId;
recv_data >> mailboxGuid;
recv_data >> mailId;
recv_data.read_skip<uint64>(); // original sender GUID for return to, not used
if (!CheckMailBox(mailboxGuid))
return;
Player* pl = _player;
Mail* m = pl->GetMail(mailId);
if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL))
{
pl->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_ERR_INTERNAL_ERROR);
return;
}
// we can return mail now
// so firstly delete the old one
CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", mailId);
// needed?
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE mail_id = '%u'", mailId);
CharacterDatabase.CommitTransaction();
pl->RemoveMail(mailId);
// send back only to existing players and simple drop for other cases
if (m->messageType == MAIL_NORMAL && m->sender)
{
MailDraft draft;
if (m->mailTemplateId)
draft.SetMailTemplate(m->mailTemplateId, false);// items already included
else
draft.SetSubjectAndBody(m->subject, m->body);
if (m->HasItems())
{
for (MailItemInfoVec::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2)
{
if (Item* item = pl->GetMItem(itr2->item_guid))
draft.AddItem(item);
pl->RemoveMItem(itr2->item_guid);
}
}
draft.SetMoney(m->money).SendReturnToSender(GetAccountId(), m->receiverGuid, ObjectGuid(HIGHGUID_PLAYER, m->sender));
}
delete m; // we can deallocate old mail
pl->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_OK);
}
/**
* Handles the packet sent by the client when taking an item from the mail.
*/
void WorldSession::HandleMailTakeItem(WorldPacket& recv_data)
{
ObjectGuid mailboxGuid;
uint32 mailId;
uint32 itemId;
recv_data >> mailboxGuid;
recv_data >> mailId;
recv_data >> itemId; // item guid low
if (!CheckMailBox(mailboxGuid))
return;
Player* pl = _player;
Mail* m = pl->GetMail(mailId);
if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL))
{
pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR);
return;
}
// prevent cheating with skip client money check
if (pl->GetMoney() < m->COD)
{
pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY);
return;
}
Item* it = pl->GetMItem(itemId);
ItemPosCountVec dest;
InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, it, false);
if (msg == EQUIP_ERR_OK)
{
m->RemoveItem(itemId);
m->removedItems.push_back(itemId);
if (m->COD > 0) // if there is COD, take COD money from player and send them to sender by mail
{
ObjectGuid sender_guid = ObjectGuid(HIGHGUID_PLAYER, m->sender);
Player* sender = sObjectMgr.GetPlayer(sender_guid);
uint32 sender_accId = 0;
if (GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE))
{
std::string sender_name;
if (sender)
{
sender_accId = sender->GetSession()->GetAccountId();
sender_name = sender->GetName();
}
else if (sender_guid)
{
// can be calculated early
sender_accId = sObjectMgr.GetPlayerAccountIdByGUID(sender_guid);
if (!sObjectMgr.GetPlayerNameByGUID(sender_guid, sender_name))
sender_name = sObjectMgr.GetMangosStringForDBCLocale(LANG_UNKNOWN);
}
sLog.outCommand(GetAccountId(), "GM %s (Account: %u) receive mail item: %s (Entry: %u Count: %u) and send COD money: %u to player: %s (Account: %u)",
GetPlayerName(), GetAccountId(), it->GetProto()->Name1, it->GetEntry(), it->GetCount(), m->COD, sender_name.c_str(), sender_accId);
}
else if (!sender)
sender_accId = sObjectMgr.GetPlayerAccountIdByGUID(sender_guid);
// check player existence
if (sender || sender_accId)
{
MailDraft(m->subject, "")
.SetMoney(m->COD)
.SendMailTo(MailReceiver(sender, sender_guid), _player, MAIL_CHECK_MASK_COD_PAYMENT);
}
pl->ModifyMoney(-int64(m->COD));
}
m->COD = 0;
m->state = MAIL_STATE_CHANGED;
pl->m_mailsUpdated = true;
pl->RemoveMItem(it->GetGUIDLow());
uint32 count = it->GetCount(); // save counts before store and possible merge with deleting
pl->MoveItemToInventory(dest, it, true);
CharacterDatabase.BeginTransaction();
pl->SaveInventoryAndGoldToDB();
pl->_SaveMail();
CharacterDatabase.CommitTransaction();
pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_OK, 0, itemId, count);
}
else
pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_EQUIP_ERROR, msg);
}
/**
* Handles the packet sent by the client when taking money from the mail.
*/
void WorldSession::HandleMailTakeMoney(WorldPacket& recv_data)
{
ObjectGuid mailboxGuid;
uint32 mailId;
uint64 money;
recv_data >> mailboxGuid;
recv_data >> mailId;
recv_data >> money;
if (!CheckMailBox(mailboxGuid))
return;
Player* pl = _player;
Mail* m = pl->GetMail(mailId);
if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL))
{
pl->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_INTERNAL_ERROR);
return;
}
pl->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK);
pl->ModifyMoney(m->money);
m->money = 0;
m->state = MAIL_STATE_CHANGED;
pl->m_mailsUpdated = true;
// save money and mail to prevent cheating
CharacterDatabase.BeginTransaction();
pl->SaveGoldToDB();
pl->_SaveMail();
CharacterDatabase.CommitTransaction();
}
/**
* Handles the packet sent by the client when requesting the current mail list.
* It will send a list of all available mails in the players mailbox to the client.
*/
void WorldSession::HandleGetMailList(WorldPacket& recv_data)
{
ObjectGuid mailboxGuid;
recv_data >> mailboxGuid;
if (!CheckMailBox(mailboxGuid))
return;
// client can't work with packets > max int16 value
const uint32 maxPacketSize = 32767;
uint32 mailsCount = 0; // send to client mails amount
uint32 realCount = 0; // real mails amount
WorldPacket data(SMSG_MAIL_LIST_RESULT, 200); // guess size
data << uint32(0); // real mail's count
data << uint8(0); // mail's count
time_t cur_time = time(NULL);
for (PlayerMails::iterator itr = _player->GetMailBegin(); itr != _player->GetMailEnd(); ++itr)
{
// packet send mail count as uint8, prevent overflow
if (mailsCount >= 254)
{
realCount += 1;
continue;
}
// skip deleted or not delivered (deliver delay not expired) mails
if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time)
continue;
uint8 item_count = (*itr)->items.size(); // max count is MAX_MAIL_ITEMS (12)
size_t next_mail_size = 2 + 4 + 1 + ((*itr)->messageType == MAIL_NORMAL ? 8 : 4) + 4 * 8 + ((*itr)->subject.size() + 1) + ((*itr)->body.size() + 1) + 1 + item_count * (1 + 4 + 4 + 7 * 3 * 4 + 4 + 4 + 4 + 4 + 4 + 4 + 1);
if (data.wpos() + next_mail_size > maxPacketSize)
{
realCount += 1;
continue;
}
data << uint16(next_mail_size); // Message size
data << uint32((*itr)->messageID); // Message ID
data << uint8((*itr)->messageType); // Message Type
switch ((*itr)->messageType)
{
case MAIL_NORMAL: // sender guid
data << ObjectGuid(HIGHGUID_PLAYER, (*itr)->sender);
break;
case MAIL_CREATURE:
case MAIL_GAMEOBJECT:
case MAIL_AUCTION:
data << uint32((*itr)->sender); // creature/gameobject entry, auction id
break;
case MAIL_CALENDAR:
data << uint32(0); // unknown
break;
}
data << uint64((*itr)->COD); // COD
data << uint32(0); // unknown, probably changed in 3.3.3
data << uint32((*itr)->stationery); // stationery (Stationery.dbc)
data << uint64((*itr)->money); // copper
data << uint32((*itr)->checked); // flags
data << float(float((*itr)->expire_time - time(NULL)) / float(DAY));// Time
data << uint32((*itr)->mailTemplateId); // mail template (MailTemplate.dbc)
data << (*itr)->subject; // Subject string - once 00, when mail type = 3, max 256
data << (*itr)->body; // message? max 8000
data << uint8(item_count); // client limit is 0x10
for (uint8 i = 0; i < item_count; ++i)
{
Item* item = _player->GetMItem((*itr)->items[i].item_guid);
// item index (0-6?)
data << uint8(i);
// item guid low?
data << uint32(item ? item->GetGUIDLow() : 0);
// entry
data << uint32(item ? item->GetEntry() : 0);
for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j)
{
// unsure
data << uint32(item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0);
// unsure
data << uint32(item ? item->GetEnchantmentDuration((EnchantmentSlot)j) : 0);
// unsure
data << uint32(item ? item->GetEnchantmentId((EnchantmentSlot)j) : 0);
}
// can be negative
data << uint32(item ? item->GetItemRandomPropertyId() : 0);
// unk
data << uint32(item ? item->GetItemSuffixFactor() : 0);
// stack count
data << uint32(item ? item->GetCount() : 0);
// charges
data << uint32(item ? item->GetSpellCharges() : 0);
// durability
data << uint32(item ? item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) : 0);
// durability
data << uint32(item ? item->GetUInt32Value(ITEM_FIELD_DURABILITY) : 0);
// unknown wotlk
data << uint8(0);
}
mailsCount += 1;
realCount += 1;
}
data.put<uint32>(0, realCount); // this will display warning about undelivered mail to player if realCount > mailsCount
data.put<uint8>(4, mailsCount); // set real send mails to client
SendPacket(&data);
// recalculate m_nextMailDelivereTime and unReadMails
_player->UpdateNextMailTimeAndUnreads();
}
/*
* Handles the packet sent by the client when he copies the body a mail to his inventory.
*
* When a player copies the body of a mail to his inventory this method is called. It will create
* a new item with the text of the mail and store it in the players inventory (if possible).
*
*/
void WorldSession::HandleMailCreateTextItem(WorldPacket& recv_data)
{
ObjectGuid mailboxGuid;
uint32 mailId;
recv_data >> mailboxGuid;
recv_data >> mailId;
if (!CheckMailBox(mailboxGuid))
return;
Player* pl = _player;
Mail* m = pl->GetMail(mailId);
if (!m || (m->body.empty() && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL))
{
pl->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR);
return;
}
Item* bodyItem = new Item; // This is not bag and then can be used new Item.
if (!bodyItem->Create(sObjectMgr.GenerateItemLowGuid(), MAIL_BODY_ITEM_TEMPLATE, pl))
{
delete bodyItem;
return;
}
// in mail template case we need create new item text
if (m->mailTemplateId)
{
MailTemplateEntry const* mailTemplateEntry = sMailTemplateStore.LookupEntry(m->mailTemplateId);
if (!mailTemplateEntry)
{
pl->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR);
return;
}
bodyItem->SetText(mailTemplateEntry->content[GetSessionDbcLocale()]);
}
else
bodyItem->SetText(m->body);
bodyItem->SetGuidValue(ITEM_FIELD_CREATOR, ObjectGuid(HIGHGUID_PLAYER, m->sender));
bodyItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_READABLE | ITEM_DYNFLAG_UNK15 | ITEM_DYNFLAG_UNK16);
DETAIL_LOG("HandleMailCreateTextItem mailid=%u", mailId);
ItemPosCountVec dest;
InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, bodyItem, false);
if (msg == EQUIP_ERR_OK)
{
m->checked = m->checked | MAIL_CHECK_MASK_COPIED;
m->state = MAIL_STATE_CHANGED;
pl->m_mailsUpdated = true;
pl->StoreItem(dest, bodyItem, true);
pl->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_OK);
}
else
{
pl->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_EQUIP_ERROR, msg);
delete bodyItem;
}
}
/**
* No idea when this is called.
*/
void WorldSession::HandleQueryNextMailTime(WorldPacket & /**recv_data*/)
{
WorldPacket data(MSG_QUERY_NEXT_MAIL_TIME, 8);
if (_player->unReadMails > 0)
{
data << uint32(0); // float
data << uint32(0); // count
uint32 count = 0;
time_t now = time(NULL);
for (PlayerMails::iterator itr = _player->GetMailBegin(); itr != _player->GetMailEnd(); ++itr)
{
Mail* m = (*itr);
// must be not checked yet
if (m->checked & MAIL_CHECK_MASK_READ)
continue;
// and already delivered
if (now < m->deliver_time)
continue;
data << ObjectGuid(HIGHGUID_PLAYER, m->sender); // sender guid
switch (m->messageType)
{
case MAIL_AUCTION:
data << uint32(m->sender); // auction house id
data << uint32(MAIL_AUCTION); // message type
break;
default:
data << uint32(0);
data << uint32(0);
break;
}
data << uint32(m->stationery);
data << uint32(0xC6000000); // float unk, time or something
++count;
if (count == 2) // do not display more than 2 mails
break;
}
data.put<uint32>(4, count);
}
else
{
data << uint32(0xC7A8C000);
data << uint32(0x00000000);
}
SendPacket(&data);
}
void WorldSession::SendShowMailBox(ObjectGuid guid)
{
WorldPacket data(SMSG_SHOW_MAILBOX, 8);
data << ObjectGuid(guid);
SendPacket(&data);
}
/*! @} */

View file

@ -1,895 +0,0 @@
/**
* This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Common.h"
#include "Language.h"
#include "Database/DatabaseEnv.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "Opcodes.h"
#include "Log.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Player.h"
#include "GossipDef.h"
#include "UpdateMask.h"
#include "ScriptMgr.h"
#include "Creature.h"
#include "Pet.h"
#include "Guild.h"
#include "GuildMgr.h"
#include "Chat.h"
enum StableResultCode
{
STABLE_ERR_MONEY = 0x01, // "you don't have enough money"
STABLE_INVALID_SLOT = 0x03,
STABLE_ERR_STABLE = 0x06, // currently used in most fail cases
STABLE_SUCCESS_STABLE = 0x08, // stable success
STABLE_SUCCESS_UNSTABLE = 0x09, // unstable/swap success
STABLE_SUCCESS_BUY_SLOT = 0x0A, // buy slot success
STABLE_ERR_EXOTIC = 0x0B, // "you are unable to control exotic creatures"
STABLE_ERR_INTERNAL = 0x0C,
};
void WorldSession::HandleTabardVendorActivateOpcode(WorldPacket& recv_data)
{
ObjectGuid guid;
recv_data >> guid;
Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TABARDDESIGNER);
if (!unit)
{
DEBUG_LOG("WORLD: HandleTabardVendorActivateOpcode - %s not found or you can't interact with him.", guid.GetString().c_str());
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
SendTabardVendorActivate(guid);
}
void WorldSession::SendTabardVendorActivate(ObjectGuid guid)
{
WorldPacket data(MSG_TABARDVENDOR_ACTIVATE, 8);
data << ObjectGuid(guid);
SendPacket(&data);
}
void WorldSession::HandleBankerActivateOpcode(WorldPacket& recv_data)
{
ObjectGuid guid;
DEBUG_LOG("WORLD: Received opcode CMSG_BANKER_ACTIVATE");
recv_data >> guid;
if (!CheckBanker(guid))
return;
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
SendShowBank(guid);
}
void WorldSession::SendShowBank(ObjectGuid guid)
{
WorldPacket data(SMSG_SHOW_BANK, 8);
data << ObjectGuid(guid);
SendPacket(&data);
}
void WorldSession::HandleTrainerListOpcode(WorldPacket& recv_data)
{
ObjectGuid guid;
recv_data >> guid;
SendTrainerList(guid);
}
void WorldSession::SendTrainerList(ObjectGuid guid)
{
std::string str = GetMangosString(LANG_NPC_TAINER_HELLO);
SendTrainerList(guid, str);
}
static void SendTrainerSpellHelper(WorldPacket& data, TrainerSpell const* tSpell, TrainerSpellState state, float fDiscountMod, bool can_learn_primary_prof, uint32 reqLevel)
{
bool primary_prof_first_rank = sSpellMgr.IsPrimaryProfessionFirstRankSpell(tSpell->learnedSpell);
SpellChainNode const* chain_node = sSpellMgr.GetSpellChainNode(tSpell->learnedSpell);
data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case)
data << uint8(state == TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state);
data << uint32(floor(tSpell->spellCost * fDiscountMod));
data << uint8(reqLevel);
data << uint32(tSpell->reqSkill);
data << uint32(tSpell->reqSkillValue);
data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0);
// primary prof. learn confirmation dialog
data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state
data << uint32(!tSpell->IsCastable() && chain_node ? (chain_node->prev ? chain_node->prev : chain_node->req) : 0);
data << uint32(!tSpell->IsCastable() && chain_node && chain_node->prev ? chain_node->req : 0);
}
void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle)
{
DEBUG_LOG("WORLD: SendTrainerList");
Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER);
if (!unit)
{
DEBUG_LOG("WORLD: SendTrainerList - %s not found or you can't interact with him.", guid.GetString().c_str());
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
// trainer list loaded at check;
if (!unit->IsTrainerOf(_player, true))
return;
CreatureInfo const* ci = unit->GetCreatureInfo();
if (!ci)
return;
TrainerSpellData const* cSpells = unit->GetTrainerSpells();
TrainerSpellData const* tSpells = unit->GetTrainerTemplateSpells();
if (!cSpells && !tSpells)
{
DEBUG_LOG("WORLD: SendTrainerList - Training spells not found for %s", guid.GetString().c_str());
return;
}
uint32 maxcount = (cSpells ? cSpells->spellList.size() : 0) + (tSpells ? tSpells->spellList.size() : 0);
uint32 trainer_type = 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);
size_t count_pos = data.wpos();
data << uint32(maxcount);
// reputation discount
float fDiscountMod = _player->GetReputationPriceDiscount(unit);
bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProfessionPoints() > 0;
uint32 count = 0;
if (cSpells)
{
for (TrainerSpellMap::const_iterator itr = cSpells->spellList.begin(); itr != cSpells->spellList.end(); ++itr)
{
TrainerSpell const* tSpell = &itr->second;
uint32 reqLevel = 0;
if (!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell, &reqLevel))
continue;
reqLevel = tSpell->isProvidedReqLevel ? tSpell->reqLevel : std::max(reqLevel, tSpell->reqLevel);
TrainerSpellState state = _player->GetTrainerSpellState(tSpell, reqLevel);
SendTrainerSpellHelper(data, tSpell, state, fDiscountMod, can_learn_primary_prof, reqLevel);
++count;
}
}
if (tSpells)
{
for (TrainerSpellMap::const_iterator itr = tSpells->spellList.begin(); itr != tSpells->spellList.end(); ++itr)
{
TrainerSpell const* tSpell = &itr->second;
uint32 reqLevel = 0;
if (!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell, &reqLevel))
continue;
reqLevel = tSpell->isProvidedReqLevel ? tSpell->reqLevel : std::max(reqLevel, tSpell->reqLevel);
TrainerSpellState state = _player->GetTrainerSpellState(tSpell, reqLevel);
SendTrainerSpellHelper(data, tSpell, state, fDiscountMod, can_learn_primary_prof, reqLevel);
++count;
}
}
data << strTitle;
data.put<uint32>(count_pos, count);
SendPacket(&data);
}
void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recv_data)
{
ObjectGuid guid;
uint32 spellId = 0, trainerId = 0;
recv_data >> guid >> trainerId >> 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);
if (!unit)
{
DEBUG_LOG("WORLD: HandleTrainerBuySpellOpcode - %s not found or you can't interact with him.", guid.GetString().c_str());
return;
}
WorldPacket sendData(SMSG_TRAINER_SERVICE, 16);
uint32 trainState = 2;
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
if (!unit->IsTrainerOf(_player, true))
trainState = 1;
// check present spell in trainer spell list
TrainerSpellData const* cSpells = unit->GetTrainerSpells();
TrainerSpellData const* tSpells = unit->GetTrainerTemplateSpells();
if (!cSpells && !tSpells)
trainState = 1;
// Try find spell in npc_trainer
TrainerSpell const* trainer_spell = cSpells ? cSpells->Find(spellId) : NULL;
// Not found, try find in npc_trainer_template
if (!trainer_spell && tSpells)
trainer_spell = tSpells->Find(spellId);
// Not found anywhere, cheating?
if (!trainer_spell)
trainState = 1;
// can't be learn, cheat? Or double learn with lags...
uint32 reqLevel = 0;
if (!_player->IsSpellFitByClassAndRace(trainer_spell->learnedSpell, &reqLevel))
trainState = 1;
reqLevel = trainer_spell->isProvidedReqLevel ? trainer_spell->reqLevel : std::max(reqLevel, trainer_spell->reqLevel);
if (_player->GetTrainerSpellState(trainer_spell, reqLevel) != TRAINER_SPELL_GREEN)
trainState = 1;
// apply reputation discount
uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit)));
// check money requirement
if (_player->GetMoney() < nSpellCost && trainState > 1)
trainState = 0;
if (trainState != 2)
{
sendData << ObjectGuid(guid);
sendData << uint32(spellId);
sendData << uint32(trainState);
SendPacket(&sendData);
}
else
{
_player->ModifyMoney(-int64(nSpellCost));
// visual effect on trainer
WorldPacket data;
unit->BuildSendPlayVisualPacket(&data, 0xB3, false);
SendPacket(&data);
// visual effect on player
_player->BuildSendPlayVisualPacket(&data, 0x016A, true);
SendPacket(&data);
// learn explicitly or cast explicitly
// TODO - Are these spells really cast correctly this way?
if (trainer_spell->IsCastable())
_player->CastSpell(_player, trainer_spell->spell, true);
else
_player->learnSpell(spellId, false);
sendData << ObjectGuid(guid);
sendData << uint32(spellId); // should be same as in packet from client
sendData << uint32(trainState);
SendPacket(&sendData);
}
}
void WorldSession::HandleGossipHelloOpcode(WorldPacket& recv_data)
{
DEBUG_LOG("WORLD: Received opcode CMSG_GOSSIP_HELLO");
ObjectGuid guid;
recv_data >> guid;
Creature* pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
if (!pCreature)
{
DEBUG_LOG("WORLD: HandleGossipHelloOpcode - %s not found or you can't interact with him.", guid.GetString().c_str());
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
pCreature->StopMoving();
if (pCreature->isSpiritGuide())
pCreature->SendAreaSpiritHealerQueryOpcode(_player);
if (!sScriptMgr.OnGossipHello(_player, pCreature))
{
_player->PrepareGossipMenu(pCreature, pCreature->GetCreatureInfo()->GossipMenuId);
_player->SendPreparedGossip(pCreature);
}
}
void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket& recv_data)
{
DEBUG_LOG("WORLD: CMSG_GOSSIP_SELECT_OPTION");
uint32 gossipListId;
uint32 menuId;
ObjectGuid guid;
std::string code;
recv_data >> guid >> menuId >> gossipListId;
if (_player->PlayerTalkClass->GossipOptionCoded(gossipListId))
{
recv_data >> code;
DEBUG_LOG("Gossip code: %s", code.c_str());
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
uint32 sender = _player->PlayerTalkClass->GossipOptionSender(gossipListId);
uint32 action = _player->PlayerTalkClass->GossipOptionAction(gossipListId);
if (guid.IsAnyTypeCreature())
{
Creature* pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
if (!pCreature)
{
DEBUG_LOG("WORLD: HandleGossipSelectOptionOpcode - %s not found or you can't interact with it.", guid.GetString().c_str());
return;
}
if (!sScriptMgr.OnGossipSelect(_player, pCreature, sender, action, code.empty() ? NULL : code.c_str()))
_player->OnGossipSelect(pCreature, gossipListId, menuId);
}
else if (guid.IsGameObject())
{
GameObject* pGo = GetPlayer()->GetGameObjectIfCanInteractWith(guid);
if (!pGo)
{
DEBUG_LOG("WORLD: HandleGossipSelectOptionOpcode - %s not found or you can't interact with it.", guid.GetString().c_str());
return;
}
if (!sScriptMgr.OnGossipSelect(_player, pGo, sender, action, code.empty() ? NULL : code.c_str()))
_player->OnGossipSelect(pGo, gossipListId, menuId);
}
}
void WorldSession::HandleSpiritHealerActivateOpcode(WorldPacket& recv_data)
{
DEBUG_LOG("WORLD: CMSG_SPIRIT_HEALER_ACTIVATE");
ObjectGuid guid;
recv_data >> guid;
Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_SPIRITHEALER);
if (!unit)
{
DEBUG_LOG("WORLD: HandleSpiritHealerActivateOpcode - %s not found or you can't interact with him.", guid.GetString().c_str());
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
SendSpiritResurrect();
}
void WorldSession::SendSpiritResurrect()
{
_player->ResurrectPlayer(0.5f, true);
_player->DurabilityLossAll(0.25f, true);
// get corpse nearest graveyard
WorldSafeLocsEntry const* corpseGrave = NULL;
Corpse* corpse = _player->GetCorpse();
if (corpse)
corpseGrave = sObjectMgr.GetClosestGraveYard(
corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam());
// now can spawn bones
_player->SpawnCorpseBones();
// teleport to nearest from corpse graveyard, if different from nearest to player ghost
if (corpseGrave)
{
WorldSafeLocsEntry const* ghostGrave = sObjectMgr.GetClosestGraveYard(
_player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam());
if (corpseGrave != ghostGrave)
_player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation());
// or update at original position
else
{
_player->GetCamera().UpdateVisibilityForOwner();
_player->UpdateObjectVisibility();
}
}
// or update at original position
else
{
_player->GetCamera().UpdateVisibilityForOwner();
_player->UpdateObjectVisibility();
}
}
void WorldSession::HandleBinderActivateOpcode(WorldPacket& recv_data)
{
ObjectGuid npcGuid;
recv_data >> npcGuid;
if (!GetPlayer()->IsInWorld() || !GetPlayer()->isAlive())
return;
Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_INNKEEPER);
if (!unit)
{
DEBUG_LOG("WORLD: HandleBinderActivateOpcode - %s not found or you can't interact with him.", npcGuid.GetString().c_str());
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
SendBindPoint(unit);
}
void WorldSession::SendBindPoint(Creature* npc)
{
// prevent set homebind to instances in any case
if (GetPlayer()->GetMap()->Instanceable())
return;
// send spell for bind 3286 bind magic
npc->CastSpell(_player, 3286, true); // Bind
WorldPacket data(SMSG_TRAINER_SERVICE, 16);
data << npc->GetObjectGuid();
data << uint32(3286); // Bind
data << uint32(2);
SendPacket(&data);
_player->PlayerTalkClass->CloseGossip();
}
void WorldSession::HandleListStabledPetsOpcode(WorldPacket& recv_data)
{
DEBUG_LOG("WORLD: Recv MSG_LIST_STABLED_PETS");
ObjectGuid npcGUID;
recv_data >> npcGUID;
if (!CheckStableMaster(npcGUID))
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
SendStablePet(npcGUID);
}
void WorldSession::SendStablePet(ObjectGuid guid)
{
DEBUG_LOG("WORLD: Recv MSG_LIST_STABLED_PETS Send.");
WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size
data << guid;
Pet* pet = _player->GetPet();
size_t wpos = data.wpos();
data << uint8(0); // place holder for slot show number
data << uint8(GetPlayer()->m_stableSlots);
uint8 num = 0; // counter for place holder
// not let move dead pet in slot
if (pet && pet->isAlive() && pet->getPetType() == HUNTER_PET)
{
data << uint32(pet->GetCharmInfo()->GetPetNumber());
data << uint32(pet->GetEntry());
data << uint32(pet->getLevel());
data << pet->GetName(); // petname
data << uint8(1); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
++num;
}
// 0 1 2 3 4
QueryResult* result = CharacterDatabase.PQuery("SELECT owner, id, entry, level, name FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot",
_player->GetGUIDLow(), PET_SAVE_FIRST_STABLE_SLOT, PET_SAVE_LAST_STABLE_SLOT);
if (result)
{
do
{
Field* fields = result->Fetch();
data << uint32(fields[1].GetUInt32()); // petnumber
data << uint32(fields[2].GetUInt32()); // creature entry
data << uint32(fields[3].GetUInt32()); // level
data << fields[4].GetString(); // name
data << uint8(2); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
++num;
}
while (result->NextRow());
delete result;
}
data.put<uint8>(wpos, num); // set real data to placeholder
SendPacket(&data);
}
void WorldSession::SendStableResult(uint8 res)
{
WorldPacket data(SMSG_STABLE_RESULT, 1);
data << uint8(res);
SendPacket(&data);
}
bool WorldSession::CheckStableMaster(ObjectGuid guid)
{
// spell case or GM
if (guid == GetPlayer()->GetObjectGuid())
{
// command case will return only if player have real access to command
if (!GetPlayer()->HasAuraType(SPELL_AURA_OPEN_STABLE) && !ChatHandler(GetPlayer()).FindCommand("stable"))
{
DEBUG_LOG("%s attempt open stable in cheating way.", guid.GetString().c_str());
return false;
}
}
// stable master case
else
{
if (!GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_STABLEMASTER))
{
DEBUG_LOG("Stablemaster %s not found or you can't interact with him.", guid.GetString().c_str());
return false;
}
}
return true;
}
void WorldSession::HandleStablePet(WorldPacket& recv_data)
{
DEBUG_LOG("WORLD: Recv CMSG_STABLE_PET");
ObjectGuid npcGUID;
recv_data >> npcGUID;
if (!GetPlayer()->isAlive())
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
if (!CheckStableMaster(npcGUID))
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
Pet* pet = _player->GetPet();
// can't place in stable dead pet
if (!pet || !pet->isAlive() || pet->getPetType() != HUNTER_PET)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
uint32 free_slot = 1;
QueryResult* result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot ",
_player->GetGUIDLow(), PET_SAVE_FIRST_STABLE_SLOT, PET_SAVE_LAST_STABLE_SLOT);
if (result)
{
do
{
Field* fields = result->Fetch();
uint32 slot = fields[1].GetUInt32();
// slots ordered in query, and if not equal then free
if (slot != free_slot)
break;
// this slot not free, skip
++free_slot;
}
while (result->NextRow());
delete result;
}
if (free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots)
{
pet->Unsummon(PetSaveMode(free_slot), _player);
SendStableResult(STABLE_SUCCESS_STABLE);
}
else
SendStableResult(STABLE_ERR_STABLE);
}
void WorldSession::HandleUnstablePet(WorldPacket& recv_data)
{
DEBUG_LOG("WORLD: Recv CMSG_UNSTABLE_PET.");
ObjectGuid npcGUID;
uint32 petnumber;
recv_data >> npcGUID >> petnumber;
if (!CheckStableMaster(npcGUID))
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
uint32 creature_id = 0;
{
QueryResult* result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot >='%u' AND slot <= '%u'",
_player->GetGUIDLow(), petnumber, PET_SAVE_FIRST_STABLE_SLOT, PET_SAVE_LAST_STABLE_SLOT);
if (result)
{
Field* fields = result->Fetch();
creature_id = fields[0].GetUInt32();
delete result;
}
}
if (!creature_id)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
CreatureInfo const* creatureInfo = ObjectMgr::GetCreatureTemplate(creature_id);
if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
{
// if problem in exotic pet
if (creatureInfo && creatureInfo->isTameable(true))
SendStableResult(STABLE_ERR_EXOTIC);
else
SendStableResult(STABLE_ERR_STABLE);
return;
}
Pet* pet = _player->GetPet();
if (pet && pet->isAlive())
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// delete dead pet
if (pet)
pet->Unsummon(PET_SAVE_AS_DELETED, _player);
Pet* newpet = new Pet(HUNTER_PET);
if (!newpet->LoadPetFromDB(_player, creature_id, petnumber))
{
delete newpet;
newpet = NULL;
SendStableResult(STABLE_ERR_STABLE);
return;
}
SendStableResult(STABLE_SUCCESS_UNSTABLE);
}
void WorldSession::HandleBuyStableSlot(WorldPacket& recv_data)
{
DEBUG_LOG("WORLD: Recv CMSG_BUY_STABLE_SLOT.");
ObjectGuid npcGUID;
recv_data >> npcGUID;
if (!CheckStableMaster(npcGUID))
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
}
void WorldSession::HandleStableRevivePet(WorldPacket &/* recv_data */)
{
DEBUG_LOG("HandleStableRevivePet: Not implemented");
}
void WorldSession::HandleStableSwapPet(WorldPacket& recv_data)
{
DEBUG_LOG("WORLD: Recv CMSG_STABLE_SWAP_PET.");
ObjectGuid npcGUID;
uint32 pet_number;
recv_data >> npcGUID >> pet_number;
if (!CheckStableMaster(npcGUID))
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
Pet* pet = _player->GetPet();
if (!pet || pet->getPetType() != HUNTER_PET)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// find swapped pet slot in stable
QueryResult* result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",
_player->GetGUIDLow(), pet_number);
if (!result)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
Field* fields = result->Fetch();
uint32 slot = fields[0].GetUInt32();
uint32 creature_id = fields[1].GetUInt32();
delete result;
if (!creature_id)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
CreatureInfo const* creatureInfo = ObjectMgr::GetCreatureTemplate(creature_id);
if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets()))
{
// if problem in exotic pet
if (creatureInfo && creatureInfo->isTameable(true))
SendStableResult(STABLE_ERR_EXOTIC);
else
SendStableResult(STABLE_ERR_STABLE);
return;
}
// move alive pet to slot or delete dead pet
pet->Unsummon(pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED, _player);
// summon unstabled pet
Pet* newpet = new Pet;
if (!newpet->LoadPetFromDB(_player, creature_id, pet_number))
{
delete newpet;
SendStableResult(STABLE_ERR_STABLE);
}
else
SendStableResult(STABLE_SUCCESS_UNSTABLE);
}
void WorldSession::HandleRepairItemOpcode(WorldPacket& recv_data)
{
DEBUG_LOG("WORLD: CMSG_REPAIR_ITEM");
ObjectGuid npcGuid;
ObjectGuid itemGuid;
uint8 guildBank; // new in 2.3.2, bool that means from guild bank money
recv_data >> npcGuid >> itemGuid >> guildBank;
Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_REPAIR);
if (!unit)
{
DEBUG_LOG("WORLD: HandleRepairItemOpcode - %s not found or you can't interact with him.", npcGuid.GetString().c_str());
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
// reputation discount
float discountMod = _player->GetReputationPriceDiscount(unit);
uint32 TotalCost = 0;
if (itemGuid)
{
DEBUG_LOG("ITEM: %s repair of %s", npcGuid.GetString().c_str(), itemGuid.GetString().c_str());
Item* item = _player->GetItemByGuid(itemGuid);
if (item)
TotalCost = _player->DurabilityRepair(item->GetPos(), true, discountMod, (guildBank > 0));
}
else
{
DEBUG_LOG("ITEM: %s repair all items", npcGuid.GetString().c_str());
TotalCost = _player->DurabilityRepairAll(true, discountMod, (guildBank > 0));
}
if (guildBank)
{
uint32 GuildId = _player->GetGuildId();
if (!GuildId)
return;
Guild* pGuild = sGuildMgr.GetGuildById(GuildId);
if (!pGuild)
return;
pGuild->LogBankEvent(GUILD_BANK_LOG_REPAIR_MONEY, 0, _player->GetGUIDLow(), TotalCost);
pGuild->SendMoneyInfo(this, _player->GetGUIDLow());
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,937 +0,0 @@
/**
* This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __SPELL_H
#define __SPELL_H
#include "Common.h"
#include "GridDefines.h"
#include "SharedDefines.h"
#include "DBCEnums.h"
#include "ObjectGuid.h"
#include "LootMgr.h"
#include "Unit.h"
#include "Player.h"
class WorldSession;
class WorldPacket;
class DynamicObj;
class Item;
class GameObject;
class Group;
class Aura;
enum SpellCastFlags
{
CAST_FLAG_NONE = 0x00000000,
CAST_FLAG_HIDDEN_COMBATLOG = 0x00000001, // hide in combat log?
CAST_FLAG_UNKNOWN2 = 0x00000002,
CAST_FLAG_UNKNOWN3 = 0x00000004,
CAST_FLAG_UNKNOWN4 = 0x00000008,
CAST_FLAG_UNKNOWN5 = 0x00000010,
CAST_FLAG_AMMO = 0x00000020, // Projectiles visual
CAST_FLAG_UNKNOWN7 = 0x00000040, // !0x41 mask used to call CGTradeSkillInfo::DoRecast
CAST_FLAG_UNKNOWN8 = 0x00000080,
CAST_FLAG_UNKNOWN9 = 0x00000100,
CAST_FLAG_UNKNOWN10 = 0x00000200,
CAST_FLAG_UNKNOWN11 = 0x00000400,
CAST_FLAG_PREDICTED_POWER = 0x00000800, // wotlk, trigger rune cooldown
CAST_FLAG_UNKNOWN13 = 0x00001000,
CAST_FLAG_UNKNOWN14 = 0x00002000,
CAST_FLAG_UNKNOWN15 = 0x00004000,
CAST_FLAG_UNKNOWN16 = 0x00008000,
CAST_FLAG_UNKNOWN17 = 0x00010000,
CAST_FLAG_ADJUST_MISSILE = 0x00020000, // wotlk
CAST_FLAG_UNKNOWN19 = 0x00040000, // spell cooldown related (may be category cooldown)
CAST_FLAG_VISUAL_CHAIN = 0x00080000, // wotlk
CAST_FLAG_UNKNOWN21 = 0x00100000,
CAST_FLAG_PREDICTED_RUNES = 0x00200000, // wotlk, rune cooldown list
CAST_FLAG_IMMUNITY = 0x04000000, // spell cast school imminity info
CAST_FLAG_UNKNOWN24 = 0x08000000,
CAST_FLAG_UNKNOWN25 = 0x10000000,
CAST_FLAG_UNKNOWN26 = 0x20000000,
CAST_FLAG_HEAL_PREDICTION = 0x40000000, // heal prediction
CAST_FLAG_UNKNOWN28 = 0x80000000,
};
enum SpellFlags
{
SPELL_FLAG_NORMAL = 0x00,
SPELL_FLAG_REFLECTED = 0x01, // reflected spell
SPELL_FLAG_REDIRECTED = 0x02 // redirected spell
};
enum SpellNotifyPushType
{
PUSH_IN_FRONT,
PUSH_IN_FRONT_90,
PUSH_IN_FRONT_30,
PUSH_IN_FRONT_15,
PUSH_IN_BACK,
PUSH_SELF_CENTER,
PUSH_DEST_CENTER,
PUSH_TARGET_CENTER
};
bool IsQuestTameSpell(uint32 spellId);
namespace MaNGOS
{
struct SpellNotifierPlayer;
struct SpellNotifierCreatureAndPlayer;
}
class SpellCastTargets;
struct SpellCastTargetsReader
{
explicit SpellCastTargetsReader(SpellCastTargets& _targets, Unit* _caster) : targets(_targets), caster(_caster) {}
SpellCastTargets& targets;
Unit* caster;
};
class SpellCastTargets
{
public:
SpellCastTargets();
~SpellCastTargets();
void read(ByteBuffer& data, Unit* caster);
void write(ByteBuffer& data) const;
SpellCastTargetsReader ReadForCaster(Unit* caster) { return SpellCastTargetsReader(*this, caster); }
void ReadAdditionalData(WorldPacket& data, uint8& cast_flags);
SpellCastTargets& operator=(const SpellCastTargets& target)
{
m_unitTarget = target.m_unitTarget;
m_itemTarget = target.m_itemTarget;
m_GOTarget = target.m_GOTarget;
m_unitTargetGUID = target.m_unitTargetGUID;
m_GOTargetGUID = target.m_GOTargetGUID;
m_CorpseTargetGUID = target.m_CorpseTargetGUID;
m_itemTargetGUID = target.m_itemTargetGUID;
m_srcTransportGUID = target.m_srcTransportGUID;
m_destTransportGUID = target.m_destTransportGUID;
m_itemTargetEntry = target.m_itemTargetEntry;
m_srcX = target.m_srcX;
m_srcY = target.m_srcY;
m_srcZ = target.m_srcZ;
m_destX = target.m_destX;
m_destY = target.m_destY;
m_destZ = target.m_destZ;
m_strTarget = target.m_strTarget;
m_targetMask = target.m_targetMask;
m_elevation = target.m_elevation;
m_speed = target.m_speed;
return *this;
}
void setUnitTarget(Unit* target);
ObjectGuid getUnitTargetGuid() const { return m_unitTargetGUID; }
Unit* getUnitTarget() const { return m_unitTarget; }
void setDestination(float x, float y, float z);
void setSource(float x, float y, float z);
void getDestination(float& x, float& y, float& z) const { x = m_destX; y = m_destY; z = m_destZ; }
void getSource(float& x, float& y, float& z) const { x = m_srcX; y = m_srcY, z = m_srcZ; }
void setGOTarget(GameObject* target);
ObjectGuid getGOTargetGuid() const { return m_GOTargetGUID; }
GameObject* getGOTarget() const { return m_GOTarget; }
void setCorpseTarget(Corpse* corpse);
ObjectGuid getCorpseTargetGuid() const { return m_CorpseTargetGUID; }
void setItemTarget(Item* item);
ObjectGuid getItemTargetGuid() const { return m_itemTargetGUID; }
Item* getItemTarget() const { return m_itemTarget; }
uint32 getItemTargetEntry() const { return m_itemTargetEntry; }
void setTradeItemTarget(Player* caster);
void updateTradeSlotItem()
{
if (m_itemTarget && (m_targetMask & TARGET_FLAG_TRADE_ITEM))
{
m_itemTargetGUID = m_itemTarget->GetObjectGuid();
m_itemTargetEntry = m_itemTarget->GetEntry();
}
}
bool IsEmpty() const { return !m_GOTargetGUID && !m_unitTargetGUID && !m_itemTarget && !m_CorpseTargetGUID; }
void Update(Unit* caster);
float m_srcX, m_srcY, m_srcZ;
float m_destX, m_destY, m_destZ;
std::string m_strTarget;
float GetElevation() const { return m_elevation; }
float GetSpeed() const { return m_speed; }
uint32 m_targetMask;
private:
// objects (can be used at spell creating and after Update at casting
Unit* m_unitTarget;
GameObject* m_GOTarget;
Item* m_itemTarget;
// object GUID/etc, can be used always
ObjectGuid m_unitTargetGUID;
ObjectGuid m_GOTargetGUID;
ObjectGuid m_CorpseTargetGUID;
ObjectGuid m_itemTargetGUID;
ObjectGuid m_srcTransportGUID;
ObjectGuid m_destTransportGUID;
uint32 m_itemTargetEntry;
float m_elevation;
float m_speed;
};
inline ByteBuffer& operator<< (ByteBuffer& buf, SpellCastTargets const& targets)
{
targets.write(buf);
return buf;
}
inline ByteBuffer& operator>> (ByteBuffer& buf, SpellCastTargetsReader const& targets)
{
targets.targets.read(buf, targets.caster);
return buf;
}
enum SpellState
{
SPELL_STATE_PREPARING = 0, // cast time delay period, non channeled spell
SPELL_STATE_CASTING = 1, // channeled time period spell casting state
SPELL_STATE_FINISHED = 2, // cast finished to success or fail
SPELL_STATE_DELAYED = 3 // spell casted but need time to hit target(s)
};
enum SpellTargets
{
SPELL_TARGETS_HOSTILE,
SPELL_TARGETS_NOT_FRIENDLY,
SPELL_TARGETS_NOT_HOSTILE,
SPELL_TARGETS_FRIENDLY,
SPELL_TARGETS_AOE_DAMAGE,
SPELL_TARGETS_ALL
};
typedef std::multimap<uint64, uint64> SpellTargetTimeMap;
class Spell
{
friend struct MaNGOS::SpellNotifierPlayer;
friend struct MaNGOS::SpellNotifierCreatureAndPlayer;
friend void Unit::SetCurrentCastedSpell(Spell* pSpell);
public:
void EffectEmpty(SpellEffectEntry const* effect);
void EffectNULL(SpellEffectEntry const* effect);
void EffectUnused(SpellEffectEntry const* effect);
void EffectDistract(SpellEffectEntry const* effect);
void EffectPull(SpellEffectEntry const* effect);
void EffectSchoolDMG(SpellEffectEntry const* effect);
void EffectEnvironmentalDMG(SpellEffectEntry const* effect);
void EffectInstaKill(SpellEffectEntry const* effect);
void EffectDummy(SpellEffectEntry const* effect);
void EffectTeleportUnits(SpellEffectEntry const* effect);
void EffectApplyAura(SpellEffectEntry const* effect);
void EffectSendEvent(SpellEffectEntry const* effect);
void EffectPowerBurn(SpellEffectEntry const* effect);
void EffectPowerDrain(SpellEffectEntry const* effect);
void EffectHeal(SpellEffectEntry const* effect);
void EffectBind(SpellEffectEntry const* effect);
void EffectHealthLeech(SpellEffectEntry const* effect);
void EffectQuestComplete(SpellEffectEntry const* effect);
void EffectCreateItem(SpellEffectEntry const* effect);
void EffectCreateItem2(SpellEffectEntry const* effect);
void EffectCreateRandomItem(SpellEffectEntry const* effect);
void EffectPersistentAA(SpellEffectEntry const* effect);
void EffectEnergize(SpellEffectEntry const* effect);
void EffectOpenLock(SpellEffectEntry const* effect);
void EffectSummonChangeItem(SpellEffectEntry const* effect);
void EffectProficiency(SpellEffectEntry const* effect);
void EffectApplyAreaAura(SpellEffectEntry const* effect);
void EffectSummonType(SpellEffectEntry const* effect);
void EffectLearnSpell(SpellEffectEntry const* effect);
void EffectDispel(SpellEffectEntry const* effect);
void EffectDualWield(SpellEffectEntry const* effect);
void EffectPickPocket(SpellEffectEntry const* effect);
void EffectAddFarsight(SpellEffectEntry const* effect);
void EffectHealMechanical(SpellEffectEntry const* effect);
void EffectJump(SpellEffectEntry const* effect);
void EffectTeleUnitsFaceCaster(SpellEffectEntry const* effect);
void EffectLearnSkill(SpellEffectEntry const* effect);
void EffectTradeSkill(SpellEffectEntry const* effect);
void EffectEnchantItemPerm(SpellEffectEntry const* effect);
void EffectEnchantItemTmp(SpellEffectEntry const* effect);
void EffectTameCreature(SpellEffectEntry const* effect);
void EffectSummonPet(SpellEffectEntry const* effect);
void EffectLearnPetSpell(SpellEffectEntry const* effect);
void EffectWeaponDmg(SpellEffectEntry const* effect);
void EffectClearQuest(SpellEffectEntry const* effect);
void EffectForceCast(SpellEffectEntry const* effect);
void EffectTriggerSpell(SpellEffectEntry const* effect);
void EffectTriggerMissileSpell(SpellEffectEntry const* effect);
void EffectThreat(SpellEffectEntry const* effect);
void EffectRestoreItemCharges(SpellEffectEntry const* effect);
void EffectHealMaxHealth(SpellEffectEntry const* effect);
void EffectInterruptCast(SpellEffectEntry const* effect);
void EffectSummonObjectWild(SpellEffectEntry const* effect);
void EffectScriptEffect(SpellEffectEntry const* effect);
void EffectSanctuary(SpellEffectEntry const* effect);
void EffectAddComboPoints(SpellEffectEntry const* effect);
void EffectDuel(SpellEffectEntry const* effect);
void EffectStuck(SpellEffectEntry const* effect);
void EffectSummonPlayer(SpellEffectEntry const* effect);
void EffectActivateObject(SpellEffectEntry const* effect);
void EffectApplyGlyph(SpellEffectEntry const* effect);
void EffectEnchantHeldItem(SpellEffectEntry const* effect);
void EffectSummonObject(SpellEffectEntry const* effect);
void EffectResurrect(SpellEffectEntry const* effect);
void EffectParry(SpellEffectEntry const* effect);
void EffectBlock(SpellEffectEntry const* effect);
void EffectLeapForward(SpellEffectEntry const* effect);
void EffectLeapBack(SpellEffectEntry const* effect);
void EffectTransmitted(SpellEffectEntry const* effect);
void EffectDisEnchant(SpellEffectEntry const* effect);
void EffectInebriate(SpellEffectEntry const* effect);
void EffectFeedPet(SpellEffectEntry const* effect);
void EffectDismissPet(SpellEffectEntry const* effect);
void EffectReputation(SpellEffectEntry const* effect);
void EffectSelfResurrect(SpellEffectEntry const* effect);
void EffectSkinning(SpellEffectEntry const* effect);
void EffectCharge(SpellEffectEntry const* effect);
void EffectCharge2(SpellEffectEntry const* effect);
void EffectProspecting(SpellEffectEntry const* effect);
void EffectRedirectThreat(SpellEffectEntry const* effect);
void EffectMilling(SpellEffectEntry const* effect);
void EffectRenamePet(SpellEffectEntry const* effect);
void EffectSendTaxi(SpellEffectEntry const* effect);
void EffectKnockBack(SpellEffectEntry const* effect);
void EffectPlayerPull(SpellEffectEntry const* effect);
void EffectDispelMechanic(SpellEffectEntry const* effect);
void EffectSummonDeadPet(SpellEffectEntry const* effect);
void EffectSummonAllTotems(SpellEffectEntry const* effect);
void EffectBreakPlayerTargeting (SpellEffectEntry const* effect);
void EffectDestroyAllTotems(SpellEffectEntry const* effect);
void EffectDurabilityDamage(SpellEffectEntry const* effect);
void EffectSkill(SpellEffectEntry const* effect);
void EffectTaunt(SpellEffectEntry const* effect);
void EffectDurabilityDamagePCT(SpellEffectEntry const* effect);
void EffectModifyThreatPercent(SpellEffectEntry const* effect);
void EffectResurrectNew(SpellEffectEntry const* effect);
void EffectAddExtraAttacks(SpellEffectEntry const* effect);
void EffectSpiritHeal(SpellEffectEntry const* effect);
void EffectSkinPlayerCorpse(SpellEffectEntry const* effect);
void EffectStealBeneficialBuff(SpellEffectEntry const* effect);
void EffectUnlearnSpecialization(SpellEffectEntry const* effect);
void EffectHealPct(SpellEffectEntry const* effect);
void EffectEnergisePct(SpellEffectEntry const* effect);
void EffectTriggerSpellWithValue(SpellEffectEntry const* effect);
void EffectTriggerRitualOfSummoning(SpellEffectEntry const* effect);
void EffectKillCreditPersonal(SpellEffectEntry const* effect);
void EffectKillCreditGroup(SpellEffectEntry const* effect);
void EffectQuestFail(SpellEffectEntry const* effect);
void EffectQuestOffer(SpellEffectEntry const* effect);
void EffectActivateRune(SpellEffectEntry const* effect);
void EffectTeachTaxiNode(SpellEffectEntry const* effect);
void EffectWMODamage(SpellEffectEntry const* effect);
void EffectWMORepair(SpellEffectEntry const* effect);
void EffectWMOChange(SpellEffectEntry const* effect);
void EffectTitanGrip(SpellEffectEntry const* effect);
void EffectEnchantItemPrismatic(SpellEffectEntry const* effect);
void EffectPlaySound(SpellEffectEntry const* effect);
void EffectPlayMusic(SpellEffectEntry const* effect);
void EffectSpecCount(SpellEffectEntry const* effect);
void EffectActivateSpec(SpellEffectEntry const* effect);
void EffectCancelAura(SpellEffectEntry const* effect);
void EffectKnockBackFromPosition(SpellEffectEntry const* effect);
Spell(Unit* caster, SpellEntry const* info, bool triggered, ObjectGuid originalCasterGUID = ObjectGuid(), SpellEntry const* triggeredBy = NULL);
~Spell();
void prepare(SpellCastTargets const* targets, Aura* triggeredByAura = NULL);
void cancel();
void update(uint32 difftime);
void cast(bool skipCheck = false);
void finish(bool ok = true);
void TakePower();
void TakeRunePower(bool hit);
void TakeAmmo();
void TakeReagents();
void TakeCastItem();
SpellCastResult CheckCast(bool strict);
SpellCastResult CheckPetCast(Unit* target);
// handlers
void handle_immediate();
uint64 handle_delayed(uint64 t_offset);
// handler helpers
void _handle_immediate_phase();
void _handle_finish_phase();
SpellCastResult CheckItems();
SpellCastResult CheckRange(bool strict);
SpellCastResult CheckPower();
SpellCastResult CheckRunePower();
SpellCastResult CheckCasterAuras() const;
int32 CalculateDamage(SpellEffectIndex i, Unit* target) { return m_caster->CalculateSpellDamage(target, m_spellInfo, i, &m_currentBasePoints[i]); }
static uint32 CalculatePowerCost(SpellEntry const* spellInfo, Unit* caster, Spell const* spell = NULL, Item* castItem = NULL);
bool HaveTargetsForEffect(SpellEffectIndex effect) const;
void Delayed();
void DelayedChannel();
uint32 getState() const { return m_spellState; }
void setState(uint32 state) { m_spellState = state; }
void DoCreateItem(SpellEffectEntry const* effect, uint32 itemtype);
void WriteSpellGoTargets(WorldPacket* data);
void WriteAmmoToPacket(WorldPacket* data);
template<typename T> WorldObject* FindCorpseUsing();
bool CheckTarget(Unit* target, SpellEffectIndex eff);
bool CanAutoCast(Unit* target);
static void MANGOS_DLL_SPEC SendCastResult(Player* caster, SpellEntry const* spellInfo, uint8 cast_count, SpellCastResult result, bool isPetCastResult = false);
void SendCastResult(SpellCastResult result);
void SendSpellStart();
void SendSpellGo();
void SendSpellCooldown();
void SendLogExecute();
void SendInterrupted(uint8 result);
void SendChannelUpdate(uint32 time);
void SendChannelStart(uint32 duration);
void SendResurrectRequest(Player* target);
void SendPlaySpellVisual(uint32 SpellID);
void HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOTarget, SpellEffectIndex i, float DamageMultiplier = 1.0);
void HandleThreatSpells();
// void HandleAddAura(Unit* Target);
SpellEntry const* m_spellInfo;
SpellEntry const* m_triggeredBySpellInfo;
SpellInterruptsEntry const* m_spellInterrupts;
int32 m_currentBasePoints[MAX_EFFECT_INDEX]; // cache SpellEntry::CalculateSimpleValue and use for set custom base points
Item* m_CastItem;
uint8 m_cast_count;
uint32 m_glyphIndex;
SpellCastTargets m_targets;
int32 GetCastTime() const { return m_casttime; }
uint32 GetCastedTime() { return m_timer; }
bool IsAutoRepeat() const { return m_autoRepeat; }
void SetAutoRepeat(bool rep) { m_autoRepeat = rep; }
void ReSetTimer() { m_timer = m_casttime > 0 ? m_casttime : 0; }
bool IsNextMeleeSwingSpell() const
{
return m_spellInfo->HasAttribute(SPELL_ATTR_ON_NEXT_SWING_1) || m_spellInfo->HasAttribute(SPELL_ATTR_ON_NEXT_SWING_2);
}
bool IsRangedSpell() const
{
return m_spellInfo->HasAttribute(SPELL_ATTR_RANGED);
}
bool IsChannelActive() const { return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0; }
bool IsMeleeAttackResetSpell() const { return !m_IsTriggeredSpell && m_spellInterrupts && (m_spellInterrupts->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK); }
bool IsRangedAttackResetSpell() const { return !m_IsTriggeredSpell && IsRangedSpell() && m_spellInterrupts && (m_spellInterrupts->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK); }
bool IsDeletable() const { return !m_referencedFromCurrentSpell && !m_executedCurrently; }
void SetReferencedFromCurrent(bool yes) { m_referencedFromCurrentSpell = yes; }
void SetExecutedCurrently(bool yes) { m_executedCurrently = yes; }
uint64 GetDelayStart() const { return m_delayStart; }
void SetDelayStart(uint64 m_time) { m_delayStart = m_time; }
uint64 GetDelayMoment() const { return m_delayMoment; }
bool IsNeedSendToClient() const; // use for hide spell cast for client in case when cast not have client side affect (animation or log entries)
bool IsTriggeredSpellWithRedundentCastTime() const; // use for ignore some spell data for triggered spells like cast time, some triggered spells have redundent copy data from main spell for client use purpose
CurrentSpellTypes GetCurrentContainer();
// caster types:
// formal spell caster, in game source of spell affects cast
Unit* GetCaster() const { return m_caster; }
// real source of cast affects, explicit caster, or DoT/HoT applier, or GO owner, or wild GO itself. Can be NULL
WorldObject* GetAffectiveCasterObject() const;
// limited version returning NULL in cases wild gameobject caster object, need for Aura (auras currently not support non-Unit caster)
Unit* GetAffectiveCaster() const { return m_originalCasterGUID ? m_originalCaster : m_caster; }
// m_originalCasterGUID can store GO guid, and in this case this is visual caster
WorldObject* GetCastingObject() const;
uint32 GetPowerCost() const { return m_powerCost; }
uint32 GetUsedHolyPower() const { return m_usedHolyPower; }
void UpdatePointers(); // must be used at call Spell code after time delay (non triggered spell cast/update spell call/etc)
bool CheckTargetCreatureType(Unit* target) const;
void AddTriggeredSpell(SpellEntry const* spellInfo) { m_TriggerSpells.push_back(spellInfo); }
void AddPrecastSpell(SpellEntry const* spellInfo) { m_preCastSpells.push_back(spellInfo); }
void AddTriggeredSpell(uint32 spellId);
void AddPrecastSpell(uint32 spellId);
void CastPreCastSpells(Unit* target);
void CastTriggerSpells();
void CleanupTargetList();
void ClearCastItem();
static void SelectMountByAreaAndSkill(Unit* target, SpellEntry const* parentSpell, uint32 spellId75, uint32 spellId150, uint32 spellId225, uint32 spellId300, uint32 spellIdSpecial);
typedef std::list<Unit*> UnitList;
protected:
bool HasGlobalCooldown();
void TriggerGlobalCooldown();
void CancelGlobalCooldown();
void SendLoot(ObjectGuid guid, LootType loottype, LockType lockType);
bool IgnoreItemRequirements() const; // some item use spells have unexpected reagent data
void UpdateOriginalCasterPointer();
Unit* m_caster;
ObjectGuid m_originalCasterGUID; // real source of cast (aura caster/etc), used for spell targets selection
// e.g. damage around area spell trigered by victim aura and da,age emeies of aura caster
Unit* m_originalCaster; // cached pointer for m_originalCaster, updated at Spell::UpdatePointers()
Spell** m_selfContainer; // pointer to our spell container (if applicable)
// Spell data
SpellSchoolMask m_spellSchoolMask; // Spell school (can be overwrite for some spells (wand shoot for example)
WeaponAttackType m_attackType; // For weapon based attack
uint32 m_powerCost; // Calculated spell cost initialized only in Spell::prepare
uint32 m_usedHolyPower;
int32 m_casttime; // Calculated spell cast time initialized only in Spell::prepare
int32 m_duration;
bool m_canReflect; // can reflect this spell?
uint8 m_spellFlags; // for spells whose target was changed in cast i.e. due to reflect
bool m_autoRepeat;
uint8 m_runesState;
uint8 m_delayAtDamageCount;
bool isDelayableNoMore()
{
if (m_delayAtDamageCount >= 2)
return true;
++m_delayAtDamageCount;
return false;
}
// Delayed spells system
uint64 m_delayStart; // time of spell delay start, filled by event handler, zero = just started
uint64 m_delayMoment; // moment of next delay call, used internally
bool m_immediateHandled; // were immediate actions handled? (used by delayed spells only)
// These vars are used in both delayed spell system and modified immediate spell system
bool m_referencedFromCurrentSpell; // mark as references to prevent deleted and access by dead pointers
bool m_executedCurrently; // mark as executed to prevent deleted and access by dead pointers
bool m_needSpellLog; // need to send spell log?
uint8 m_applyMultiplierMask; // by effect: damage multiplier needed?
float m_damageMultipliers[3]; // by effect: damage multiplier
// Current targets, to be used in SpellEffects (MUST BE USED ONLY IN SPELL EFFECTS)
Unit* unitTarget;
Item* itemTarget;
GameObject* gameObjTarget;
SpellAuraHolder* m_spellAuraHolder; // spell aura holder for current target, created only if spell has aura applying effect
int32 damage;
// this is set in Spell Hit, but used in Apply Aura handler
DiminishingLevels m_diminishLevel;
DiminishingGroup m_diminishGroup;
// -------------------------------------------
GameObject* focusObject;
// Damage and healing in effects need just calculate
int32 m_damage; // Damage in effects count here
int32 m_healing; // Healing in effects count here
int32 m_healthLeech; // Health leech in effects for all targets count here
//******************************************
// Spell trigger system
//******************************************
bool m_canTrigger; // Can start trigger (m_IsTriggeredSpell can`t use for this)
uint8 m_negativeEffectMask; // Use for avoid sent negative spell procs for additional positive effects only targets
uint32 m_procAttacker; // Attacker trigger flags
uint32 m_procVictim; // Victim trigger flags
void prepareDataForTriggerSystem();
//*****************************************
// Spell target filling
//*****************************************
void FillTargetMap();
void SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& targetUnitMap);
void FillAreaTargets(UnitList& targetUnitMap, float radius, SpellNotifyPushType pushType, SpellTargets spellTargets, WorldObject* originalCaster = NULL);
void FillRaidOrPartyTargets(UnitList& targetUnitMap, Unit* member, Unit* center, float radius, bool raid, bool withPets, bool withcaster);
void FillRaidOrPartyManaPriorityTargets(UnitList& targetUnitMap, Unit* member, Unit* center, float radius, uint32 count, bool raid, bool withPets, bool withcaster);
void FillRaidOrPartyHealthPriorityTargets(UnitList& targetUnitMap, Unit* member, Unit* center, float radius, uint32 count, bool raid, bool withPets, bool withcaster);
// Returns a target that was filled by SPELL_SCRIPT_TARGET (or selected victim) Can return NULL
Unit* GetPrefilledUnitTargetOrUnitTarget(SpellEffectIndex effIndex) const;
void GetSpellRangeAndRadius(SpellEffectEntry const* spellEffect, float& radius, uint32& EffectChainTarget, uint32& unMaxTargets) const;
//*****************************************
// Spell target subsystem
//*****************************************
// Targets store structures and data
struct TargetInfo
{
ObjectGuid targetGUID;
uint64 timeDelay;
uint32 HitInfo;
uint32 damage;
SpellMissInfo missCondition: 8;
SpellMissInfo reflectResult: 8;
uint8 effectMask: 8;
bool processed: 1;
};
uint8 m_needAliveTargetMask; // Mask req. alive targets
struct GOTargetInfo
{
ObjectGuid targetGUID;
uint64 timeDelay;
uint8 effectMask: 8;
bool processed: 1;
};
struct ItemTargetInfo
{
Item* item;
uint8 effectMask;
};
typedef std::list<TargetInfo> TargetList;
typedef std::list<GOTargetInfo> GOTargetList;
typedef std::list<ItemTargetInfo> ItemTargetList;
TargetList m_UniqueTargetInfo;
GOTargetList m_UniqueGOTargetInfo;
ItemTargetList m_UniqueItemInfo;
void AddUnitTarget(Unit* target, SpellEffectIndex effIndex);
void AddUnitTarget(ObjectGuid unitGuid, SpellEffectIndex effIndex);
void AddGOTarget(GameObject* target, SpellEffectIndex effIndex);
void AddGOTarget(ObjectGuid goGuid, SpellEffectIndex effIndex);
void AddItemTarget(Item* target, SpellEffectIndex effIndex);
void DoAllEffectOnTarget(TargetInfo* target);
void HandleDelayedSpellLaunch(TargetInfo* target);
void InitializeDamageMultipliers();
void ResetEffectDamageAndHeal();
void DoSpellHitOnUnit(Unit* unit, uint32 effectMask);
void DoAllEffectOnTarget(GOTargetInfo* target);
void DoAllEffectOnTarget(ItemTargetInfo* target);
bool IsAliveUnitPresentInTargetList();
SpellCastResult CanOpenLock(SpellEffectIndex effIndex, uint32 lockid, SkillType& skillid, int32& reqSkillValue, int32& skillValue);
// -------------------------------------------
// List For Triggered Spells
typedef std::list<SpellEntry const*> SpellInfoList;
SpellInfoList m_TriggerSpells; // casted by caster to same targets settings in m_targets at success finish of current spell
SpellInfoList m_preCastSpells; // casted by caster to each target at spell hit before spell effects apply
uint32 m_spellState;
uint32 m_timer;
float m_castPositionX;
float m_castPositionY;
float m_castPositionZ;
float m_castOrientation;
bool m_IsTriggeredSpell;
// if need this can be replaced by Aura copy
// we can't store original aura link to prevent access to deleted auras
// and in same time need aura data and after aura deleting.
SpellEntry const* m_triggeredByAuraSpell;
private:
// NPC Summonings
struct CreaturePosition
{
CreaturePosition() :
x(0.0f), y(0.0f), z(0.0f),
creature(NULL)
{}
float x, y, z;
Creature* creature;
};
typedef std::vector<CreaturePosition> CreatureSummonPositions;
// return true IFF further processing required
bool DoSummonPet(SpellEffectEntry const* effect);
bool DoSummonTotem(SpellEffectEntry const* effect, uint8 slot_dbc = 0);
bool DoSummonWild(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectEntry const* effect, uint32 level);
bool DoSummonCritter(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectEntry const* effect, uint32 level);
bool DoSummonGuardian(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectEntry const* effect, uint32 level);
bool DoSummonPossessed(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectEntry const* effect, uint32 level);
bool DoSummonVehicle(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectEntry const* effect, uint32 level);
};
enum ReplenishType
{
REPLENISH_UNDEFINED = 0,
REPLENISH_HEALTH = 20,
REPLENISH_MANA = 21,
REPLENISH_RAGE = 22
};
namespace MaNGOS
{
struct MANGOS_DLL_DECL SpellNotifierPlayer // Currently unused. When put to use this one requires handling for source-location (smilar to below)
{
Spell::UnitList& i_data;
Spell& i_spell;
const uint32& i_index;
float i_radius;
WorldObject* i_originalCaster;
SpellNotifierPlayer(Spell& spell, Spell::UnitList& data, const uint32& i, float radius)
: i_data(data), i_spell(spell), i_index(i), i_radius(radius)
{
i_originalCaster = i_spell.GetAffectiveCasterObject();
}
void Visit(PlayerMapType& m)
{
if (!i_originalCaster)
return;
for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
{
Player* pPlayer = itr->getSource();
if (!pPlayer->isAlive() || pPlayer->IsTaxiFlying())
continue;
if (i_originalCaster->IsFriendlyTo(pPlayer))
continue;
if (pPlayer->IsWithinDist3d(i_spell.m_targets.m_destX, i_spell.m_targets.m_destY, i_spell.m_targets.m_destZ, i_radius))
i_data.push_back(pPlayer);
}
}
template<class SKIP> void Visit(GridRefManager<SKIP>&) {}
};
struct MANGOS_DLL_DECL SpellNotifierCreatureAndPlayer
{
Spell::UnitList* i_data;
Spell& i_spell;
SpellNotifyPushType i_push_type;
float i_radius;
SpellTargets i_TargetType;
WorldObject* i_originalCaster;
WorldObject* i_castingObject;
bool i_playerControlled;
float i_centerX;
float i_centerY;
float i_centerZ;
float GetCenterX() const { return i_centerX; }
float GetCenterY() const { return i_centerY; }
SpellNotifierCreatureAndPlayer(Spell& spell, Spell::UnitList& data, float radius, SpellNotifyPushType type,
SpellTargets TargetType = SPELL_TARGETS_NOT_FRIENDLY, WorldObject* originalCaster = NULL)
: i_data(&data), i_spell(spell), i_push_type(type), i_radius(radius), i_TargetType(TargetType),
i_originalCaster(originalCaster), i_castingObject(i_spell.GetCastingObject())
{
if (!i_originalCaster)
i_originalCaster = i_spell.GetAffectiveCasterObject();
i_playerControlled = i_originalCaster ? i_originalCaster->IsControlledByPlayer() : false;
switch (i_push_type)
{
case PUSH_IN_FRONT:
case PUSH_IN_FRONT_90:
case PUSH_IN_FRONT_30:
case PUSH_IN_FRONT_15:
case PUSH_IN_BACK:
case PUSH_SELF_CENTER:
if (i_castingObject)
{
i_centerX = i_castingObject->GetPositionX();
i_centerY = i_castingObject->GetPositionY();
}
break;
case PUSH_DEST_CENTER:
if (i_spell.m_targets.m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
i_spell.m_targets.getSource(i_centerX, i_centerY, i_centerZ);
else
i_spell.m_targets.getDestination(i_centerX, i_centerY, i_centerZ);
break;
case PUSH_TARGET_CENTER:
if (Unit* target = i_spell.m_targets.getUnitTarget())
{
i_centerX = target->GetPositionX();
i_centerY = target->GetPositionY();
}
break;
default:
sLog.outError("SpellNotifierCreatureAndPlayer: unsupported PUSH_* case %u.", i_push_type);
}
}
template<class T> inline void Visit(GridRefManager<T>& m)
{
MANGOS_ASSERT(i_data);
if (!i_originalCaster || !i_castingObject)
return;
for (typename GridRefManager<T>::iterator itr = m.begin(); itr != m.end(); ++itr)
{
// there are still more spells which can be casted on dead, but
// they are no AOE and don't have such a nice SPELL_ATTR flag
if ((i_TargetType != SPELL_TARGETS_ALL && !itr->getSource()->isTargetableForAttack(i_spell.m_spellInfo->HasAttribute(SPELL_ATTR_EX3_CAST_ON_DEAD)))
// mostly phase check
|| !itr->getSource()->IsInMap(i_originalCaster))
continue;
switch (i_TargetType)
{
case SPELL_TARGETS_HOSTILE:
if (!i_originalCaster->IsHostileTo(itr->getSource()))
continue;
break;
case SPELL_TARGETS_NOT_FRIENDLY:
if (i_originalCaster->IsFriendlyTo(itr->getSource()))
continue;
break;
case SPELL_TARGETS_NOT_HOSTILE:
if (i_originalCaster->IsHostileTo(itr->getSource()))
continue;
break;
case SPELL_TARGETS_FRIENDLY:
if (!i_originalCaster->IsFriendlyTo(itr->getSource()))
continue;
break;
case SPELL_TARGETS_AOE_DAMAGE:
{
if (itr->getSource()->GetTypeId() == TYPEID_UNIT && ((Creature*)itr->getSource())->IsTotem())
continue;
if (i_playerControlled)
{
if (i_originalCaster->IsFriendlyTo(itr->getSource()))
continue;
}
else
{
if (!i_originalCaster->IsHostileTo(itr->getSource()))
continue;
}
}
break;
case SPELL_TARGETS_ALL:
break;
default: continue;
}
// we don't need to check InMap here, it's already done some lines above
switch (i_push_type)
{
case PUSH_IN_FRONT:
if (i_castingObject->isInFront((Unit*)(itr->getSource()), i_radius, 2 * M_PI_F / 3))
i_data->push_back(itr->getSource());
break;
case PUSH_IN_FRONT_90:
if (i_castingObject->isInFront((Unit*)(itr->getSource()), i_radius, M_PI_F / 2))
i_data->push_back(itr->getSource());
break;
case PUSH_IN_FRONT_30:
if (i_castingObject->isInFront((Unit*)(itr->getSource()), i_radius, M_PI_F / 6))
i_data->push_back(itr->getSource());
break;
case PUSH_IN_FRONT_15:
if (i_castingObject->isInFront((Unit*)(itr->getSource()), i_radius, M_PI_F / 12))
i_data->push_back(itr->getSource());
break;
case PUSH_IN_BACK:
if (i_castingObject->isInBack((Unit*)(itr->getSource()), i_radius, 2 * M_PI_F / 3))
i_data->push_back(itr->getSource());
break;
case PUSH_SELF_CENTER:
if (i_castingObject->IsWithinDist((Unit*)(itr->getSource()), i_radius))
i_data->push_back(itr->getSource());
break;
case PUSH_DEST_CENTER:
if (itr->getSource()->IsWithinDist3d(i_centerX, i_centerY, i_centerZ, i_radius))
i_data->push_back(itr->getSource());
break;
case PUSH_TARGET_CENTER:
if (i_spell.m_targets.getUnitTarget() && i_spell.m_targets.getUnitTarget()->IsWithinDist((Unit*)(itr->getSource()), i_radius))
i_data->push_back(itr->getSource());
break;
}
}
}
#ifdef WIN32
template<> inline void Visit(CorpseMapType&) {}
template<> inline void Visit(GameObjectMapType&) {}
template<> inline void Visit(DynamicObjectMapType&) {}
template<> inline void Visit(CameraMapType&) {}
#endif
};
#ifndef WIN32
template<> inline void SpellNotifierCreatureAndPlayer::Visit(CorpseMapType&) {}
template<> inline void SpellNotifierCreatureAndPlayer::Visit(GameObjectMapType&) {}
template<> inline void SpellNotifierCreatureAndPlayer::Visit(DynamicObjectMapType&) {}
template<> inline void SpellNotifierCreatureAndPlayer::Visit(CameraMapType&) {}
#endif
}
typedef void(Spell::*pEffect)(SpellEffectEntry const* spellEffect);
class SpellEvent : public BasicEvent
{
public:
SpellEvent(Spell* spell);
virtual ~SpellEvent();
virtual bool Execute(uint64 e_time, uint32 p_time) override;
virtual void Abort(uint64 e_time) override;
virtual bool IsDeletable() const override;
protected:
Spell* m_Spell;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,27 @@
/**
* MaNGOS is a full featured server for World of Warcraft, supporting
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
*
* Copyright (C) 2005-2015 MaNGOS project <http://getmangos.eu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
* and lore are copyrighted by Blizzard Entertainment, Inc.
*/
// add here most rarely modified headers to speed up debug build compilation
#include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it
#include "Common.h"