Mant more cmangos Cata commits applied

Commit:
This commit is contained in:
Charles A Edwards 2016-08-29 15:51:13 +01:00 committed by Antz
parent 6db0ba8ae9
commit 8cac2f42db
51 changed files with 964 additions and 270 deletions

View file

@ -64,9 +64,20 @@ typedef ACE_SHLIB_HANDLE MANGOS_LIBRARY_HANDLE;
# define MANGOS_EXPORT __declspec(dllexport)
# define MANGOS_IMPORT __cdecl
#else // PLATFORM != PLATFORM_WINDOWS
# include <dlfcn.h>
typedef void* MANGOS_LIBRARY_HANDLE;
# define MANGOS_LOAD_LIBRARY(libname) dlopen(libname, RTLD_LAZY)
# define MANGOS_CLOSE_LIBRARY(hlib) dlclose(hlib)
# define MANGOS_GET_PROC_ADDR(hlib, name) dlsym(hlib, name)
# define MANGOS_EXPORT export
# if defined(__APPLE_CC__) && defined(BIG_ENDIAN)
# if (defined(__ppc__) || defined(__powerpc__))
# if PLATFORM == PLATFORM_APPLE
# define MANGOS_SCRIPT_SUFFIX ".dylib"
# else
# define MANGOS_SCRIPT_SUFFIX ".so"
# endif
# define MANGOS_SCRIPT_PREFIX "lib"
# if defined(__APPLE_CC__) && defined(BIG_ENDIAN) // TODO:: more work to do with byte order. Have to be rechecked after boost integration.
# if (defined (__ppc__) || defined (__powerpc__))
# define MANGOS_IMPORT __attribute__ ((longcall))
# else
# define MANGOS_IMPORT

View file

@ -326,14 +326,7 @@ void BattleGround::Update(uint32 diff)
}
else if (m_PrematureCountDownTimer < diff)
{
// time's up!
Team winner = TEAM_NONE;
if (GetPlayersCountByTeam(ALLIANCE) >= GetMinPlayersPerTeam())
winner = ALLIANCE;
else if (GetPlayersCountByTeam(HORDE) >= GetMinPlayersPerTeam())
winner = HORDE;
EndBattleGround(winner);
EndBattleGround(GetPrematureWinner());
m_PrematureCountDown = false;
}
else if (!sBattleGroundMgr.isTesting())
@ -1483,6 +1476,19 @@ void BattleGround::DoorOpen(ObjectGuid guid)
sLog.outError("BattleGround: Door %s not found! - doors will be closed.", guid.GetString().c_str());
}
Team BattleGround::GetPrematureWinner()
{
uint32 hordePlayers = GetPlayersCountByTeam(HORDE);
uint32 alliancePlayers = GetPlayersCountByTeam(ALLIANCE);
if (hordePlayers > alliancePlayers)
return HORDE;
if (alliancePlayers > hordePlayers)
return ALLIANCE;
return TEAM_NONE;
}
void BattleGround::OnObjectDBLoad(Creature* creature)
{
const BattleGroundEventIdx eventId = sBattleGroundMgr.GetCreatureEventIndex(creature->GetGUIDLow());

View file

@ -550,6 +550,8 @@ class BattleGround
void DoorOpen(ObjectGuid guid);
void DoorClose(ObjectGuid guid);
virtual Team GetPrematureWinner();
virtual bool HandlePlayerUnderMap(Player* /*plr*/) { return false; }
// since arenas can be AvA or Hvh, we have to get the "temporary" team of a player

View file

@ -543,3 +543,18 @@ bool BattleGroundAB::IsAllNodesControlledByTeam(Team team) const
return true;
}
Team BattleGroundAB::GetPrematureWinner()
{
int32 hordeScore = m_TeamScores[TEAM_INDEX_HORDE];
int32 allianceScore = m_TeamScores[TEAM_INDEX_ALLIANCE];
if (hordeScore > allianceScore)
return HORDE;
if (allianceScore > hordeScore)
return ALLIANCE;
// If the values are equal, fall back to number of players on each team
return BattleGround::GetPrematureWinner();
}

View file

@ -189,6 +189,8 @@ class BattleGroundAB : public BattleGround
/* achievement req. */
bool IsAllNodesControlledByTeam(Team team) const override;
bool IsTeamScores500Disadvantage(Team team) const { return m_TeamScores500Disadvantage[GetTeamIndexByTeamId(team)]; }
virtual Team GetPrematureWinner() override;
private:
/* Gameobject spawning/despawning */
void _CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay);

View file

@ -823,3 +823,17 @@ void BattleGroundAV::Reset()
InitNode(BG_AV_NODES_SNOWFALL_GRAVE, BG_AV_TEAM_NEUTRAL, false); // give snowfall neutral owner
}
Team BattleGroundAV::GetPrematureWinner()
{
int32 hordeScore = m_TeamScores[TEAM_INDEX_HORDE];
int32 allianceScore = m_TeamScores[TEAM_INDEX_ALLIANCE];
if (hordeScore > allianceScore)
return HORDE;
if (allianceScore > hordeScore)
return ALLIANCE;
// If the values are equal, fall back to number of players on each team
return BattleGround::GetPrematureWinner();
}

View file

@ -359,6 +359,8 @@ class BattleGroundAV : public BattleGround
virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* plr) override;
static BattleGroundAVTeamIndex GetAVTeamIndexByTeamId(Team team) { return BattleGroundAVTeamIndex(GetTeamIndexByTeamId(team)); }
virtual Team GetPrematureWinner() override;
private:
/* Nodes occupying */
void EventPlayerAssaultsPoint(Player* player, BG_AV_Nodes node);

View file

@ -401,18 +401,6 @@ void BattleGroundEY::HandleKillPlayer(Player* player, Player* killer)
void BattleGroundEY::EventPlayerDroppedFlag(Player* source)
{
if (GetStatus() != STATUS_IN_PROGRESS)
{
// if not running, do not cast things at the dropper player, neither send unnecessary messages
// just take off the aura
if (IsFlagPickedUp() && GetFlagCarrierGuid() == source->GetObjectGuid())
{
ClearFlagCarrier();
source->RemoveAurasDueToSpell(EY_NETHERSTORM_FLAG_SPELL);
}
return;
}
if (!IsFlagPickedUp())
return;
@ -421,6 +409,13 @@ void BattleGroundEY::EventPlayerDroppedFlag(Player* source)
ClearFlagCarrier();
source->RemoveAurasDueToSpell(EY_NETHERSTORM_FLAG_SPELL);
if (GetStatus() != STATUS_IN_PROGRESS)
{
// do not cast auras or send messages after match has ended
return;
}
m_flagState = EY_FLAG_STATE_ON_GROUND;
m_flagRespawnTimer = EY_FLAG_RESPAWN_TIME;
source->CastSpell(source, SPELL_RECENTLY_DROPPED_FLAG, true);
@ -429,12 +424,12 @@ void BattleGroundEY::EventPlayerDroppedFlag(Player* source)
if (source->GetTeam() == ALLIANCE)
{
UpdateWorldState(WORLD_STATE_EY_NETHERSTORM_FLAG_STATE_ALLIANCE, 1);
SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL);
SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, nullptr);
}
else
{
UpdateWorldState(WORLD_STATE_EY_NETHERSTORM_FLAG_STATE_HORDE, 1);
SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, NULL);
SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, nullptr);
}
}
@ -625,3 +620,17 @@ bool BattleGroundEY::IsAllNodesControlledByTeam(Team team) const
return true;
}
Team BattleGroundEY::GetPrematureWinner()
{
int32 hordeScore = m_TeamScores[TEAM_INDEX_HORDE];
int32 allianceScore = m_TeamScores[TEAM_INDEX_ALLIANCE];
if (hordeScore > allianceScore)
return HORDE;
if (allianceScore > hordeScore)
return ALLIANCE;
// If the values are equal, fall back to number of players on each team
return BattleGround::GetPrematureWinner();
}

View file

@ -284,6 +284,8 @@ class BattleGroundEY : public BattleGround
/* achievement req. */
bool IsAllNodesControlledByTeam(Team team) const override;
virtual Team GetPrematureWinner() override;
private:
// process capture events
void ProcessCaptureEvent(GameObject* go, uint32 towerId, Team team, uint32 newWorldState, uint32 message);

View file

@ -652,3 +652,17 @@ void BattleGroundWS::FillInitialWorldStates(WorldPacket& data, uint32& count)
FillInitialWorldState(data, count, BG_WS_TIME_ENABLED, WORLD_STATE_ADD);
FillInitialWorldState(data, count, BG_WS_TIME_REMAINING, GetRemainingTimeInMinutes());
}
Team BattleGroundWS::GetPrematureWinner()
{
int32 hordeScore = m_TeamScores[TEAM_INDEX_HORDE];
int32 allianceScore = m_TeamScores[TEAM_INDEX_ALLIANCE];
if (hordeScore > allianceScore)
return HORDE;
if (allianceScore > hordeScore)
return ALLIANCE;
// If the values are equal, fall back to number of players on each team
return BattleGround::GetPrematureWinner();
}

View file

@ -153,6 +153,8 @@ class BattleGroundWS : public BattleGround
void ClearDroppedFlagGuid(Team team) { m_DroppedFlagGuid[GetTeamIndexByTeamId(team)].Clear();}
ObjectGuid const& GetDroppedFlagGuid(Team team) const { return m_DroppedFlagGuid[GetTeamIndexByTeamId(team)];}
virtual void FillInitialWorldStates(WorldPacket& data, uint32& count) override;
virtual Team GetPrematureWinner() override;
private:
ObjectGuid m_flagCarrierAlliance;

View file

@ -61,6 +61,7 @@
#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
#include "MoveMap.h" // for mmap manager
#include "PathFinder.h" // for mmap commands
#include "movement/MoveSplineInit.h"
static uint32 ReputationRankStrIndex[MAX_REPUTATION_RANK] =
{
@ -2919,24 +2920,21 @@ inline void UnsummonVisualWaypoints(Player const* player, ObjectGuid ownerGuid)
}
}
/**
* Add a waypoint to a creature.
/** Add a waypoint to a creature
* .wp add [dbGuid] [pathId] [source]
*
* The user can either select an npc or provide its GUID.
* The user can either select an npc or provide its dbGuid.
* Also the user can specify pathId and source if wanted.
*
* The user can even select a visual waypoint - then the new waypoint
* is placed *after* the selected one - this makes insertion of new
* waypoints possible.
*
* eg:
* .wp add 12345
* -> adds a waypoint to the npc with the GUID 12345
* .wp add [pathId] [source]
* -> adds a waypoint to the currently selected creature, to path pathId in source-storage
*
* .wp add
* -> adds a waypoint to the currently selected creature
*
*
* @param args if the user did not provide a GUID, it is NULL
* .wp add guid [pathId] [source]
* -> if no npc is selected, expect the creature provided with guid argument
*
* @return true - command did succeed, false - something went wrong
*/
@ -3079,27 +3077,42 @@ bool ChatHandler::HandleWpAddCommand(char* args)
PSendSysMessage(LANG_WAYPOINT_ADDED, wpPointId, wpOwner->GetGuidStr().c_str(), wpPathId, WaypointManager::GetOriginString(wpDestination).c_str());
return true;
} // HandleWpAddCommand
} // HandleWpAddCommand
/**
* .wp modify emote | spell | text | del | move | add
* .wp modify waittime | scriptid | orientation | del | move [dbGuid, id] [value]
*
* add -> add a WP after the selected visual waypoint
* User must select a visual waypoint and then issue ".wp modify add"
*
* emote <emoteID>
* waittime <Delay>
* User has selected a visual waypoint before.
* <emoteID> is added to this waypoint. Everytime the
* NPC comes to this waypoint, the emote is called.
* Delay <Delay> is added to this waypoint. Everytime the
* NPC comes to this waypoint, it will wait Delay millieseconds.
*
* emote <GUID> <WPNUM> <emoteID>
* waittime <DBGuid> <WPNUM> <Delay>
* User has not selected visual waypoint before.
* For the waypoint <WPNUM> for the NPC with <GUID>
* an emote <emoteID> is added.
* Everytime the NPC comes to this waypoint, the emote is called.
* For the waypoint <WPNUM> for the NPC with <DBGuid>
* an delay Delay is added to this waypoint
* Everytime the NPC comes to this waypoint, it will wait Delay millieseconds.
*
* scriptid <scriptId>
* User has selected a visual waypoint before.
* <scriptId> is added to this waypoint. Everytime the
* NPC comes to this waypoint, the DBScript scriptId is executed.
*
* info <GUID> <WPNUM> -> User did not select a visual waypoint and
* scriptid <DBGuid> <WPNUM> <scriptId>
* User has not selected visual waypoint before.
* For the waypoint <WPNUM> for the NPC with <DBGuid>
* an emote <scriptId> is added.
* Everytime the NPC comes to this waypoint, the DBScript scriptId is executed.
*
* orientation [DBGuid, WpNum] <Orientation>
* Set the orientation of the selected waypoint or waypoint given with DbGuid/ WpId
* to the value of <Orientation>.
*
* del [DBGuid, WpId]
* Remove the selected waypoint or waypoint given with DbGuid/ WpId.
*
* move [DBGuid, WpId]
* Move the selected waypoint or waypoint given with DbGuid/ WpId to player's current positiion.
*/
bool ChatHandler::HandleWpModifyCommand(char* args)
{
@ -3303,29 +3316,19 @@ bool ChatHandler::HandleWpModifyCommand(char* args)
}
/**
* .wp show info | on | off
* .wp show info | on | off | first | last [dbGuid] [pathId [wpOrigin] ]
*
* info -> User has selected a visual waypoint before
*
* info <GUID> <WPNUM> -> User did not select a visual waypoint and
* provided the GUID of the NPC and the number of
* the waypoint.
*
* on -> User has selected an NPC; all visual waypoints for this
* NPC are added to the world
*
* on <GUID> -> User did not select an NPC - instead the GUID of the
* on <dbGuid> -> User did not select an NPC - instead the dbGuid of the
* NPC is provided. All visual waypoints for this NPC
* are added from the world.
*
* off -> User has selected an NPC; all visual waypoints for this
* NPC are removed from the world.
*
* on <GUID> -> User did not select an NPC - instead the GUID of the
* NPC is provided. All visual waypoints for this NPC
* are removed from the world.
*
*
*/
bool ChatHandler::HandleWpShowCommand(char* args)
{
@ -5071,20 +5074,53 @@ bool ChatHandler::HandleMmapPathCommand(char* args)
char* para = strtok(args, " ");
bool useStraightPath = false;
if (para && strcmp(para, "true") == 0)
useStraightPath = true;
bool followPath = false;
bool unitToPlayer = false;
if (para)
{
if (strcmp(para, "go") == 0)
{
followPath = true;
para = strtok(nullptr, " ");
if (para && strcmp(para, "straight") == 0)
useStraightPath = true;
}
else if (strcmp(para, "straight") == 0)
useStraightPath = true;
else if (strcmp(para, "to_me") == 0)
unitToPlayer = true;
else
{
PSendSysMessage("Use '.mmap path go' to move on target.");
PSendSysMessage("Use '.mmap path straight' to generate straight path.");
PSendSysMessage("Use '.mmap path to_me' to generate path from the target to you.");
}
}
Unit* destinationUnit;
Unit* originUnit;
if (unitToPlayer)
{
destinationUnit = player;
originUnit = target;
}
else
{
destinationUnit = target;
originUnit = player;
}
// unit locations
float x, y, z;
player->GetPosition(x, y, z);
destinationUnit->GetPosition(x, y, z);
// path
PathFinder path(target);
PathFinder path(originUnit);
path.setUseStrightPath(useStraightPath);
path.calculate(x, y, z);
PointsArray pointPath = path.getPath();
PSendSysMessage("%s's path to %s:", target->GetName(), player->GetName());
PSendSysMessage("%s's path to %s:", originUnit->GetName(), destinationUnit->GetName());
PSendSysMessage("Building %s", useStraightPath ? "StraightPath" : "SmoothPath");
PSendSysMessage("length " SIZEFMTD " type %u", pointPath.size(), path.getPathType());
@ -5099,13 +5135,15 @@ bool ChatHandler::HandleMmapPathCommand(char* args)
if (!player->isGameMaster())
PSendSysMessage("Enable GM mode to see the path points.");
// this entry visible only to GM's with "gm on"
static const uint32 WAYPOINT_NPC_ENTRY = 1;
Creature* wp = NULL;
for (uint32 i = 0; i < pointPath.size(); ++i)
player->SummonCreature(VISUAL_WAYPOINT, pointPath[i].x, pointPath[i].y, pointPath[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 9000);
if (followPath)
{
wp = player->SummonCreature(WAYPOINT_NPC_ENTRY, pointPath[i].x, pointPath[i].y, pointPath[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 9000);
// TODO: make creature not sink/fall
Movement::MoveSplineInit init(*player);
init.MovebyPath(pointPath);
init.SetWalk(false);
init.Launch();
}
return true;

View file

@ -2302,7 +2302,7 @@ bool ChatHandler::HandleLearnAllCommand(char* /*args*/)
int loop = 0;
while (strcmp(allSpellList[loop], "0"))
{
uint32 spell = atol((char*)allSpellList[loop++]);
uint32 spell = std::stoul((char*)allSpellList[loop++]);
if (m_session->GetPlayer()->HasSpell(spell))
continue;
@ -2345,7 +2345,7 @@ bool ChatHandler::HandleLearnAllGMCommand(char* /*args*/)
uint16 gmSpellIter = 0;
while (strcmp(gmSpellList[gmSpellIter], "0"))
{
uint32 spell = atol((char*)gmSpellList[gmSpellIter++]);
uint32 spell = std::stoul((char*)gmSpellList[gmSpellIter++]);
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell);
if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo, m_session->GetPlayer()))

View file

@ -354,7 +354,7 @@ bool ChatHandler::HandleDebugGetLootRecipientCommand(char* /*args*/)
bool ChatHandler::HandleDebugSendQuestInvalidMsgCommand(char* args)
{
uint32 msg = atol(args);
uint32 msg = std::stoul(args);
m_session->GetPlayer()->SendCanTakeQuestResponse(msg);
return true;
}

View file

@ -39,7 +39,7 @@ PathFinder::PathFinder(const Unit* owner) :
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::PathInfo for %u \n", m_sourceUnit->GetGUIDLow());
uint32 mapId = m_sourceUnit->GetMapId();
if (MMAP::MMapFactory::IsPathfindingEnabled(mapId))
if (MMAP::MMapFactory::IsPathfindingEnabled(mapId, owner))
{
MMAP::MMapManager* mmap = MMAP::MMapFactory::createOrGetMMapManager();
m_navMesh = mmap->GetNavMesh(mapId);

View file

@ -1810,17 +1810,26 @@ void Creature::SetLootStatus(CreatureLootStatus status)
}
}
// return true if this creature is tapped by the player or by a member of his group.
bool Creature::IsTappedBy(Player const* player) const
// simple tap system return true if player or his group tapped the creature
// TODO:: this is semi correct. For group situation need more work but its not a big issue
bool Creature::IsTappedBy(Player* plr) const
{
if (player == GetOriginalLootRecipient())
return true;
if (Player* recipient = GetLootRecipient())
{
if (recipient == plr)
return true;
Group const* playerGroup = player->GetGroup();
if (!playerGroup || playerGroup != GetGroupLootRecipient()) // if we dont have a group we arent the recipient
return false; // if creature doesnt have group bound it means it was solo killed by someone else
return true;
if (Group* grp = recipient->GetGroup())
{
if (Group* plrGroup = plr->GetGroup())
{
if (plrGroup == grp)
return true;
}
}
return false;
}
return false;
}
SpellEntry const* Creature::ReachWithSpellAttack(Unit* pVictim)

View file

@ -66,6 +66,7 @@ enum CreatureFlagsExtra
CREATURE_EXTRA_FLAG_MMAP_FORCE_DISABLE = 0x00004000, // creature is forced to NOT use MMaps
CREATURE_EXTRA_FLAG_WALK_IN_WATER = 0x00008000, // creature is forced to walk in water even it can swim
CREATURE_EXTRA_FLAG_HAVE_NO_SWIM_ANIMATION = 0x00010000, // we have to not set "swim" animation or creature will have "no animation"
CREATURE_EXTRA_FLAG_NO_MELEE = 0x00020000, // creature can't melee
};
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform
@ -561,7 +562,7 @@ class Creature : public Unit
bool IsImmuneToSpell(SpellEntry const* spellInfo, bool castOnSelf) override;
bool IsImmuneToSpellEffect(SpellEntry const* spellInfo, SpellEffectIndex index, bool castOnSelf) const override;
void SetLootStatus(CreatureLootStatus status);
bool IsTappedBy(Player const* player) const;
bool IsTappedBy(Player* plr) const;
bool IsElite() const
{

View file

@ -79,6 +79,10 @@ GameObject::GameObject() : WorldObject(),
m_groupLootTimer = 0;
m_groupLootId = 0;
m_lootGroupRecipientId = 0;
m_isInUse = false;
m_reStockTimer = 0;
m_despawnTimer = 0;
}
GameObject::~GameObject()
@ -1951,6 +1955,7 @@ void GameObject::SetLootRecipient(Unit* pUnit)
{
m_lootRecipientGuid.Clear();
m_lootGroupRecipientId = 0;
ForceValuesUpdateAtIndex(UNIT_DYNAMIC_FLAGS); // needed to be sure tapping status is updated
return;
}
@ -1964,6 +1969,8 @@ void GameObject::SetLootRecipient(Unit* pUnit)
// set group for group existed case including if player will leave group at loot time
if (Group* group = player->GetGroup())
{ m_lootGroupRecipientId = group->GetId(); }
ForceValuesUpdateAtIndex(UNIT_DYNAMIC_FLAGS); // needed to be sure tapping status is updated
}
float GameObject::GetObjectBoundingRadius() const
@ -2402,6 +2409,15 @@ float GameObject::GetInteractionDistance()
}
}
void GameObject::SetInUse(bool use)
{
m_isInUse = use;
if (use)
SetGoState(GO_STATE_ACTIVE);
else
SetGoState(GO_STATE_READY);
}
uint32 GameObject::GetScriptId()
{
return sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, -int32(GetGUIDLow())) ? sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, -int32(GetGUIDLow())) : sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, GetEntry());

View file

@ -749,6 +749,8 @@ class GameObject : public WorldObject
void AddUniqueUse(Player* player);
void AddUse() { ++m_useTimes; }
bool IsInUse() const { return m_isInUse; }
void SetInUse(bool use);
uint32 GetUseCount() const { return m_useTimes; }
uint32 GetUniqueUseCount() const { return m_UniqueUsers.size(); }

View file

@ -800,7 +800,7 @@ bool Object::LoadValues(const char* data)
int index;
for (iter = tokens.begin(), index = 0; index < m_valuesCount; ++iter, ++index)
{
m_uint32Values[index] = atol((*iter).c_str());
m_uint32Values[index] = std::stoul((*iter).c_str());
}
return true;
@ -1119,6 +1119,16 @@ void Object::MarkForClientUpdate()
}
}
void Object::ForceValuesUpdateAtIndex(uint32 index)
{
m_changedValues[index] = true;
if (m_inWorld && !m_objectUpdated)
{
AddToClientUpdateList();
m_objectUpdated = true;
}
}
WorldObject::WorldObject() :
#ifdef ENABLE_ELUNA
elunaEvents(NULL),

View file

@ -258,6 +258,7 @@ class Object
void SetGuidValue(uint16 index, ObjectGuid const& value) { SetUInt64Value(index, value.GetRawValue()); }
void SetStatFloatValue(uint16 index, float value);
void SetStatInt32Value(uint16 index, int32 value);
void ForceValuesUpdateAtIndex(uint32 index);
void ApplyModUInt32Value(uint16 index, int32 val, bool apply);
void ApplyModInt32Value(uint16 index, int32 val, bool apply);

View file

@ -191,7 +191,7 @@ void PlayerTaxi::LoadTaxiMask(const char* data)
(index < TaxiMaskSize) && (iter != tokens.end()); ++iter, ++index)
{
// load and set bits only for existing taxi nodes
m_taximask[index] = sTaxiNodesMask[index] & uint8(atol((*iter).c_str()));
m_taximask[index] = sTaxiNodesMask[index] & uint8(std::stoul((*iter).c_str()));
}
}
@ -218,7 +218,7 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, Team
for (Tokens::iterator iter = tokens.begin(); iter != tokens.end(); ++iter)
{
uint32 node = uint32(atol(iter->c_str()));
uint32 node = std::stoul(iter->c_str());
AddTaxiDestination(node);
}
@ -2358,23 +2358,7 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid guid, uint32 gameo
{
if (uint32(go->GetGoType()) == gameobject_type || gameobject_type == MAX_GAMEOBJECT_TYPE)
{
float maxdist;
switch (go->GetGoType())
{
// TODO: find out how the client calculates the maximal usage distance to spellless working
// gameobjects like guildbanks and mailboxes - 10.0 is a just an abitrary choosen number
case GAMEOBJECT_TYPE_GUILD_BANK:
case GAMEOBJECT_TYPE_MAILBOX:
maxdist = 10.0f;
break;
case GAMEOBJECT_TYPE_FISHINGHOLE:
maxdist = 20.0f + CONTACT_DISTANCE; // max spell range
break;
default:
maxdist = INTERACTION_DISTANCE;
break;
}
float maxdist = go->GetInteractionDistance();
if (go->IsWithinDistInMap(this, maxdist) && go->isSpawned())
return go;
@ -5543,6 +5527,10 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step)
if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED)
return false;
SkillStatusData& skillStatus = itr->second;
if (skillStatus.uState == SKILL_DELETED)
return false;
uint16 field = itr->second.pos / 2;
uint8 offset = itr->second.pos & 1; // itr->second.pos % 2
@ -15349,7 +15337,7 @@ void Player::_LoadIntoDataField(const char* data, uint32 startOffset, uint32 cou
uint32 index;
for (iter = tokens.begin(), index = 0; index < count; ++iter, ++index)
{
m_uint32Values[startOffset + index] = atol((*iter).c_str());
m_uint32Values[startOffset + index] = std::stoul((*iter).c_str());
}
}

View file

@ -2076,36 +2076,40 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
// This seems to reduce the victims time until next attack if your attack was parried
if (damageInfo->TargetState == VICTIMSTATE_PARRY)
{
// Get attack timers
float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
// Reduce attack time
if (pVictim->haveOffhandWeapon() && offtime < basetime)
if (pVictim->GetTypeId() != TYPEID_UNIT ||
!(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_PARRY_HASTEN))
{
float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20f;
float percent60 = 3.0f * percent20;
if (offtime > percent20 && offtime <= percent60)
// Get attack timers
float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
// Reduce attack time
if (pVictim->haveOffhandWeapon() && offtime < basetime)
{
pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20));
float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20f;
float percent60 = 3.0f * percent20;
if (offtime > percent20 && offtime <= percent60)
{
pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20));
}
else if (offtime > percent60)
{
offtime -= 2.0f * percent20;
pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime));
}
}
else if (offtime > percent60)
else
{
offtime -= 2.0f * percent20;
pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime));
}
}
else
{
float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20f;
float percent60 = 3.0f * percent20;
if (basetime > percent20 && basetime <= percent60)
{
pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20));
}
else if (basetime > percent60)
{
basetime -= 2.0f * percent20;
pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime));
float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20f;
float percent60 = 3.0f * percent20;
if (basetime > percent20 && basetime <= percent60)
{
pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20));
}
else if (basetime > percent60)
{
basetime -= 2.0f * percent20;
pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime));
}
}
}
}
@ -10736,9 +10740,9 @@ void CharmInfo::LoadPetActionBar(const std::string& data)
for (iter = tokens.begin(), index = ACTION_BAR_INDEX_START; index < ACTION_BAR_INDEX_END; ++iter, ++index)
{
// use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion
uint8 type = (uint8)atol((*iter).c_str());
uint8 type = (uint8)std::stoul((*iter).c_str());
++iter;
uint32 action = atol((*iter).c_str());
uint32 action = std::stoul((*iter).c_str());
PetActionBar[index].SetActionAndType(action, ActiveStates(type));

View file

@ -791,6 +791,7 @@ class MovementInfo
void ChangeOrientation(float o) { pos.o = o; }
void ChangePosition(float x, float y, float z, float o) { pos.x = x; pos.y = y; pos.z = z; pos.o = o; }
void UpdateTime(uint32 _time) { time = _time; }
uint32 GetTime(){ return time; }
struct JumpInfo
{

View file

@ -465,11 +465,12 @@ enum TotemCategoryType
// SummonProperties.dbc, col 1 == Group (m_control)
enum SummonPropGroup
{
SUMMON_PROP_GROUP_WILD = 0,
SUMMON_PROP_GROUP_FRIENDLY = 1,
SUMMON_PROP_GROUP_PETS = 2,
SUMMON_PROP_GROUP_CONTROLLABLE = 3,
SUMMON_PROP_GROUP_VEHICLE = 4
SUMMON_PROP_GROUP_WILD = 0,
SUMMON_PROP_GROUP_FRIENDLY = 1,
SUMMON_PROP_GROUP_PETS = 2,
SUMMON_PROP_GROUP_CONTROLLABLE = 3,
SUMMON_PROP_GROUP_VEHICLE = 4,
SUMMON_PROP_GROUP_UNCONTROLLABLE_VEHICLE = 5
};
// SummonProperties.dbc, col 2 == FactionId (m_faction)

View file

@ -103,7 +103,7 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8
m_muteTime(mute_time), _player(NULL), m_Socket(sock), _security(sec), _accountId(id), m_expansion(expansion), _logoutTime(0),
m_inQueue(false), m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), m_playerSave(false),
m_sessionDbcLocale(sWorld.GetAvailableDbcLocale(locale)), m_sessionDbLocaleIndex(sObjectMgr.GetIndexForLocale(locale)),
m_latency(0), m_tutorialState(TUTORIALDATA_UNCHANGED)
m_latency(0), m_clientTimeDelay(0), m_tutorialState(TUTORIALDATA_UNCHANGED)
{
if (sock)
{

View file

@ -462,6 +462,7 @@ class WorldSession
m_latency = latency;
}
void SetClientTimeDelay(uint32 delay) { m_clientTimeDelay = delay; }
void ResetClientTimeDelay() { m_clientTimeDelay = 0; }
uint32 getDialogStatus(Player* pPlayer, Object* questgiver, uint32 defstatus);
public: // opcodes handlers
@ -1015,10 +1016,10 @@ class WorldSession
LocaleConstant m_sessionDbcLocale;
int m_sessionDbLocaleIndex;
uint32 m_latency;
uint32 m_clientTimeDelay;
AccountData m_accountData[NUM_ACCOUNT_DATA_TYPES];
uint32 m_Tutorials[8];
TutorialDataState m_tutorialState;
uint32 m_clientTimeDelay;
AddonsList m_addonsList;
ACE_Based::LockedQueue<WorldPacket*, ACE_Thread_Mutex> _recvQueue;
};

View file

@ -1051,17 +1051,18 @@ int WorldSocket::HandlePing(WorldPacket& recvPacket)
// critical section
{
ACE_GUARD_RETURN(LockType, Guard, m_SessionLock, -1);
if (m_Session)
{
m_Session->SetLatency(latency);
m_Session->ResetClientTimeDelay();
}
else
{
sLog.outError("WorldSocket::HandlePing: peer sent CMSG_PING, "
"but is not authenticated or got recently kicked,"
" address = %s",
GetRemoteAddress().c_str());
return -1;
return false;
}
}

View file

@ -58,6 +58,7 @@ GridMap::GridMap()
m_gridGetHeight = &GridMap::getHeightFromFlat;
m_V9 = NULL;
m_V8 = NULL;
memset(m_holes, 0, sizeof(m_holes));
// Liquid data
m_liquidType = 0;
@ -205,6 +206,16 @@ bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/)
return true;
}
bool GridMap::loadHolesData(FILE* in, uint32 offset, uint32 size)
{
if (fseek(in, offset, SEEK_SET) != 0)
return false;
if (fread(&m_holes, sizeof(m_holes), 1, in) != 1)
return false;
return true;
}
bool GridMap::loadGridMapLiquidData(FILE* in, uint32 offset, uint32 /*size*/)
{
GridMapLiquidHeader header;
@ -255,10 +266,22 @@ float GridMap::getHeightFromFlat(float /*x*/, float /*y*/) const
return m_gridHeight;
}
bool GridMap::isHole(int row, int col) const
{
int cellRow = row / 8; // 8 squares per cell
int cellCol = col / 8;
int holeRow = row % 8 / 2;
int holeCol = (col - (cellCol * 8)) / 2;
uint16 hole = m_holes[cellRow][cellCol];
return (hole & holetab_h[holeCol] & holetab_v[holeRow]) != 0;
}
float GridMap::getHeightFromFloat(float x, float y) const
{
if (!m_V8 || !m_V9)
return m_gridHeight;
return INVALID_HEIGHT_VALUE;
x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
@ -270,6 +293,9 @@ float GridMap::getHeightFromFloat(float x, float y) const
x_int &= (MAP_RESOLUTION - 1);
y_int &= (MAP_RESOLUTION - 1);
if (isHole(x_int, y_int))
return INVALID_HEIGHT_VALUE;
// Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid
// +--------------> X
// | h1-------h2 Coordinates is:

View file

@ -126,7 +126,8 @@ struct GridMapLiquidData
class GridMap
{
private:
uint16 m_holes[16][16];
uint32 m_flags;
// Area data
@ -163,6 +164,8 @@ class GridMap
bool loadAreaData(FILE* in, uint32 offset, uint32 size);
bool loadHeightData(FILE* in, uint32 offset, uint32 size);
bool loadGridMapLiquidData(FILE* in, uint32 offset, uint32 size);
bool loadHolesData(FILE* in, uint32 offset, uint32 size);
bool isHole(int row, int col) const;
// Get height functions and pointers
typedef float(GridMap::*pGetHeightPtr)(float x, float y) const;

View file

@ -84,8 +84,6 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recv_data)
DEBUG_LOG("WORLD: Received opcode CMSG_WHO");
// recv_data.hexlike();
uint32 clientcount = 0;
uint32 level_min, level_max, racemask, classmask, zones_count, str_count;
uint32 zoneids[10]; // 10 is client limit
std::string player_name, guild_name;
@ -149,9 +147,12 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recv_data)
bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST);
AccountTypes gmLevelInWhoList = (AccountTypes)sWorld.getConfig(CONFIG_UINT32_GM_LEVEL_IN_WHO_LIST);
uint32 matchcount = 0;
uint32 displaycount = 0;
WorldPacket data(SMSG_WHO, 50); // guess size
data << uint32(clientcount); // clientcount place holder, listed count
data << uint32(clientcount); // clientcount place holder, online count
data << uint32(matchcount); // clientcount place holder, listed count
data << uint32(displaycount); // clientcount place holder, online count
// TODO: Guard Player map
HashMapHolder<Player>::MapType& m = sObjectAccessor.GetPlayers();
@ -250,6 +251,8 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recv_data)
if (!s_show)
continue;
++displaycount;
data << pname; // player name
data << gname; // guild name
data << uint32(lvl); // player level
@ -257,15 +260,13 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recv_data)
data << uint32(race); // player race
data << uint8(gender); // player gender
data << uint32(pzoneid); // player zone id
// 50 is maximum player count sent to client
if ((++clientcount) == 50)
break;
}
uint32 count = m.size();
data.put(0, clientcount); // insert right count, listed count
data.put(4, count > 50 ? count : clientcount); // insert right count, online count
if (sWorld.getConfig(CONFIG_UINT32_MAX_WHOLIST_RETURNS) && matchcount > sWorld.getConfig(CONFIG_UINT32_MAX_WHOLIST_RETURNS))
matchcount = sWorld.getConfig(CONFIG_UINT32_MAX_WHOLIST_RETURNS);
data.put(0, displaycount); // insert right count, count displayed
data.put(4, matchcount); // insert right count, count of matches
SendPacket(&data);
DEBUG_LOG("WORLD: Send SMSG_WHO Message");

View file

@ -25,6 +25,7 @@
#include "GridMap.h"
#include "Log.h"
#include "World.h"
#include "Creature.h"
#include "MoveMap.h"
#include "MoveMapSharedDefines.h"
@ -65,10 +66,30 @@ namespace MMAP
delete[] mapList;
}
bool MMapFactory::IsPathfindingEnabled(uint32 mapId)
bool MMapFactory::IsPathfindingEnabled(uint32 mapId, const Unit* unit = nullptr)
{
return sWorld.getConfig(CONFIG_BOOL_MMAP_ENABLED)
&& g_mmapDisabledIds->find(mapId) == g_mmapDisabledIds->end();
if (!sWorld.getConfig(CONFIG_BOOL_MMAP_ENABLED))
return false;
if (unit)
{
// always use mmaps for players
if (unit->GetTypeId() == TYPEID_PLAYER)
return true;
if (IsPathfindingForceDisabled(unit))
return false;
if (IsPathfindingForceEnabled(unit))
return true;
// always use mmaps for pets of players (can still be disabled by extra-flag for pet creature)
if (unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->IsPet() && unit->GetOwner() &&
unit->GetOwner()->GetTypeId() == TYPEID_PLAYER)
return true;
}
return g_mmapDisabledIds->find(mapId) == g_mmapDisabledIds->end();
}
void MMapFactory::clear()
@ -80,6 +101,34 @@ namespace MMAP
g_MMapManager = NULL;
}
bool MMapFactory::IsPathfindingForceEnabled(const Unit* unit)
{
if (const Creature* pCreature = dynamic_cast<const Creature*>(unit))
{
if (const CreatureInfo* pInfo = pCreature->GetCreatureInfo())
{
if (pInfo->ExtraFlags & CREATURE_EXTRA_FLAG_MMAP_FORCE_ENABLE)
return true;
}
}
return false;
}
bool MMapFactory::IsPathfindingForceDisabled(const Unit* unit)
{
if (const Creature* pCreature = dynamic_cast<const Creature*>(unit))
{
if (const CreatureInfo* pInfo = pCreature->GetCreatureInfo())
{
if (pInfo->ExtraFlags & CREATURE_EXTRA_FLAG_MMAP_FORCE_DISABLE)
return true;
}
}
return false;
}
// ######################## MMapManager ########################
MMapManager::~MMapManager()
{

View file

@ -31,6 +31,8 @@
#include "../../dep/recastnavigation/Detour/Include/DetourNavMesh.h"
#include "../../dep/recastnavigation/Detour/Include/DetourNavMeshQuery.h"
class Unit;
// memory management
inline void* dtCustomAlloc(int size, dtAllocHint /*hint*/)
{
@ -107,7 +109,9 @@ namespace MMAP
static MMapManager* createOrGetMMapManager();
static void clear();
static void preventPathfindingOnMaps(const char* ignoreMapIds);
static bool IsPathfindingEnabled(uint32 mapId);
static bool IsPathfindingEnabled(uint32 mapId, const Unit* unit);
static bool IsPathfindingForceEnabled(const Unit* unit);
static bool IsPathfindingForceDisabled(const Unit* unit);
};
}

View file

@ -38,6 +38,8 @@
#include "MapPersistentStateMgr.h"
#include "ObjectMgr.h"
#define MOVEMENT_PACKET_TIME_DELAY 0
void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recv_data*/)
{
DEBUG_LOG("WORLD: got MSG_MOVE_WORLDPORT_ACK.");
@ -595,7 +597,9 @@ bool WorldSession::VerifyMovementInfo(MovementInfo const& movementInfo, ObjectGu
void WorldSession::HandleMoverRelocation(MovementInfo& movementInfo)
{
movementInfo.UpdateTime(WorldTimer::getMSTime());
if (m_clientTimeDelay == 0)
m_clientTimeDelay = WorldTimer::getMSTime() - movementInfo.GetTime();
movementInfo.UpdateTime(movementInfo.GetTime() + m_clientTimeDelay + MOVEMENT_PACKET_TIME_DELAY);
Unit* mover = _player->GetMover();

View file

@ -702,7 +702,7 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename)
}
break;
}
case SCRIPT_COMMAND_SEND_AI_EVENT_AROUND: // 35
case SCRIPT_COMMAND_SEND_AI_EVENT: // 35
{
if (tmp.sendAIEvent.eventType >= MAXIMAL_AI_EVENT_EVENTAI)
{
@ -717,7 +717,7 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename)
{
if (tmp.moveDynamic.maxDist < tmp.moveDynamic.minDist)
{
sLog.outErrorDb("Table `%s` has invalid min-dist (datalong2 = %u) less than max-dist (datalon = %u) in SCRIPT_COMMAND_MOVE_DYNAMIC for script id %u", tablename, tmp.moveDynamic.minDist, tmp.moveDynamic.maxDist, tmp.id);
sLog.outErrorDb("Table `%s` has invalid min-dist (datalong2 = %u) less than max-dist (datalong = %u) in SCRIPT_COMMAND_MOVE_DYNAMIC for script id %u", tablename, tmp.moveDynamic.minDist, tmp.moveDynamic.maxDist, tmp.id);
continue;
}
break;
@ -736,7 +736,36 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename)
}
break;
}
case SCRIPT_COMMAND_CHANGE_ENTRY: // 39
case SCRIPT_COMMAND_SET_FLY: // 39
case SCRIPT_COMMAND_DESPAWN_GO: // 40
case SCRIPT_COMMAND_RESPAWN: // 41
break;
case SCRIPT_COMMAND_SET_EQUIPMENT_SLOTS: // 42
{
if (tmp.textId[0] < 0 || tmp.textId[1] < 0 || tmp.textId[2] < 0)
{
sLog.outErrorDb("Table `%s` has invalid equipment slot (dataint = %u, dataint2 = %u, dataint3 = %u) in SCRIPT_COMMAND_SET_EQUIPMENT_SLOTS for script id %u", tablename, tmp.textId[0], tmp.textId[1], tmp.textId[2], tmp.id);
continue;
}
break;
}
case SCRIPT_COMMAND_RESET_GO: // 43
break;
case SCRIPT_COMMAND_UPDATE_TEMPLATE: // 44
{
if (!sCreatureStorage.LookupEntry<CreatureInfo>(tmp.updateTemplate.newTemplate))
{
sLog.outErrorDb("Table `%s` uses nonexistent creature entry %u in SCRIPT_COMMAND_UPDATE_TEMPLATE for script id %u.", tablename, tmp.updateTemplate.newTemplate, tmp.id);
continue;
}
if (tmp.updateTemplate.newFactionTeam != 0 && tmp.updateTemplate.newFactionTeam != 1)
{
sLog.outErrorDb("Table `%s` uses nonexistent faction team %u in SCRIPT_COMMAND_UPDATE_TEMPLATE for script id %u.", tablename, tmp.updateTemplate.newFactionTeam, tmp.id);
continue;
}
break;
}
case SCRIPT_COMMAND_CHANGE_ENTRY: // 45
{
if (tmp.changeEntry.creatureEntry && !ObjectMgr::GetCreatureTemplate(tmp.changeEntry.creatureEntry))
{
@ -1048,15 +1077,24 @@ bool ScriptAction::GetScriptProcessTargets(WorldObject* pOrigSource, WorldObject
if (m_script->IsCreatureBuddy())
{
Creature* pCreatureBuddy = NULL;
Creature* pCreatureBuddy = nullptr;
MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*pSearcher, m_script->buddyEntry, true, false, m_script->searchRadiusOrGuid, true);
MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(pCreatureBuddy, u_check);
if (m_script->data_flags & SCRIPT_FLAG_BUDDY_IS_DESPAWNED)
{
MaNGOS::AllCreaturesOfEntryInRangeCheck u_check(pSearcher, m_script->buddyEntry, m_script->searchRadiusOrGuid);
MaNGOS::CreatureLastSearcher<MaNGOS::AllCreaturesOfEntryInRangeCheck> searcher(pCreatureBuddy, u_check);
Cell::VisitGridObjects(pSearcher, searcher, m_script->searchRadiusOrGuid);
}
else
{
MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*pSearcher, m_script->buddyEntry, true, false, m_script->searchRadiusOrGuid, true);
MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(pCreatureBuddy, u_check);
if (m_script->data_flags & SCRIPT_FLAG_BUDDY_IS_PET)
{ Cell::VisitWorldObjects(pSearcher, searcher, m_script->searchRadiusOrGuid); }
else // Normal Creature
{ Cell::VisitGridObjects(pSearcher, searcher, m_script->searchRadiusOrGuid); }
if (m_script->data_flags & SCRIPT_FLAG_BUDDY_IS_PET)
Cell::VisitWorldObjects(pSearcher, searcher, m_script->searchRadiusOrGuid);
else // Normal Creature
Cell::VisitGridObjects(pSearcher, searcher, m_script->searchRadiusOrGuid);
}
pBuddy = pCreatureBuddy;
@ -1894,55 +1932,80 @@ bool ScriptAction::HandleScriptStep()
}
return terminateResult;
}
case SCRIPT_COMMAND_SEND_AI_EVENT_AROUND: // 35
case SCRIPT_COMMAND_SEND_AI_EVENT: // 35
{
if (LogIfNotCreature(pSource))
return false;
if (LogIfNotUnit(pTarget))
break;
((Creature*)pSource)->AI()->SendAIEventAround(AIEventType(m_script->sendAIEvent.eventType), (Unit*)pTarget, 0, float(m_script->sendAIEvent.radius));
// if radius is provided send AI event around
if (m_script->sendAIEvent.radius)
((Creature*)pSource)->AI()->SendAIEventAround(AIEventType(m_script->sendAIEvent.eventType), (Unit*)pTarget, 0, float(m_script->sendAIEvent.radius));
// else if no radius and target is creature send AI event to target
else if (pTarget->GetTypeId() == TYPEID_UNIT)
((Creature*)pSource)->AI()->SendAIEvent(AIEventType(m_script->sendAIEvent.eventType), nullptr, (Creature*)pTarget);
break;
}
case SCRIPT_COMMAND_TURN_TO: // 36
case SCRIPT_COMMAND_TURN_TO: // 36
{
if (LogIfNotUnit(pSource))
{ break; }
if (LogIfNotCreature(pSource))
return false;
Creature* pCSource = static_cast<Creature*>(pSource);
if (!pTarget)
{
sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command _SET_FACING (%u): No target found.", m_table, m_script->id, m_script->command);
return false;
}
if (m_script->turnTo.targetId)
{
float x, y, z, o;
if (pCSource->GetMotionMaster()->empty() || !pCSource->GetMotionMaster()->top()->GetResetPosition(*pCSource, x, y, z, o))
pCSource->GetRespawnCoord(x, y, z, &o);
pCSource->SetFacingTo(o);
((Unit*)pSource)->SetFacingTo(pSource->GetAngle(pTarget));
if (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL && !pCSource->IsInCombat())
pCSource->SetTargetGuid(ObjectGuid());
}
else
{
pCSource->SetFacingToObject(pTarget);
if (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL && !LogIfNotUnit(pTarget) && !pCSource->IsInCombat())
pCSource->SetTargetGuid(pTarget->GetObjectGuid());
}
break;
}
case SCRIPT_COMMAND_MOVE_DYNAMIC: // 37
{
//if (LogIfNotCreature(pSource))
// return false;
//if (LogIfNotUnit(pTarget))
// return false;
if (LogIfNotCreature(pSource))
return false;
if (LogIfNotUnit(pTarget))
return false;
//float x, y, z;
//if (m_script->moveDynamic.maxDist == 0) // Move to pTarget
//{
// if (pTarget == pSource)
// {
// sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, _MOVE_DYNAMIC called with maxDist == 0, but resultingSource == resultingTarget (== %s)", m_table, m_script->id, pSource->GetGuidStr().c_str());
// break;
// }
// pTarget->GetContactPoint(pSource, x, y, z);
//}
//else // Calculate position
//{
// float orientation;
// if (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL)
// orientation = pSource->GetOrientation() + m_script->o + 2 * M_PI_F;
// else
// orientation = m_script->o;
float x, y, z;
if (m_script->moveDynamic.maxDist == 0) // Move to pTarget
{
if (pTarget == pSource)
{
sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, _MOVE_DYNAMIC called with maxDist == 0, but resultingSource == resultingTarget (== %s)", m_table, m_script->id, pSource->GetGuidStr().c_str());
break;
}
pTarget->GetContactPoint(pSource, x, y, z);
}
else // Calculate position
{
float orientation;
if (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL)
orientation = pSource->GetOrientation() + m_script->o + 2 * M_PI_F;
else
orientation = m_script->o;
// pSource->GetRandomPoint(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), m_script->moveDynamic.maxDist, x, y, z,
// m_script->moveDynamic.minDist, (orientation == 0.0f ? NULL : &orientation));
// z = std::max(z, pTarget->GetPositionZ());
// pSource->UpdateAllowedPositionZ(x, y, z);
//}
//((Creature*)pSource)->GetMotionMaster()->MovePoint(1, x, y, z);
pSource->GetRandomPoint(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), m_script->moveDynamic.maxDist, x, y, z,
m_script->moveDynamic.minDist, (orientation == 0.0f ? nullptr : &orientation));
z = std::max(z, pTarget->GetPositionZ());
pSource->UpdateAllowedPositionZ(x, y, z);
}
((Creature*)pSource)->GetMotionMaster()->MovePoint(1, x, y, z);
break;
}
case SCRIPT_COMMAND_SEND_MAIL: // 38
@ -1962,7 +2025,98 @@ bool ScriptAction::HandleScriptStep()
MailDraft(m_script->sendMail.mailTemplateId).SendMailTo(static_cast<Player*>(pTarget), sender, MAIL_CHECK_MASK_HAS_BODY, deliverDelay);
break;
}
case SCRIPT_COMMAND_CHANGE_ENTRY: // 39
case SCRIPT_COMMAND_SET_FLY: // 39
{
if (LogIfNotCreature(pSource))
break;
// enable / disable the fly anim flag
if (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL)
{
if (m_script->fly.fly)
pSource->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM);
else
pSource->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM);
}
((Creature*)pSource)->SetLevitate(!!m_script->fly.fly);
break;
}
case SCRIPT_COMMAND_DESPAWN_GO: // 40
{
if (LogIfNotGameObject(pTarget))
break;
// ToDo: Change this to pGo->ForcedDespawn() when function is implemented!
((GameObject*)pTarget)->SetLootState(GO_JUST_DEACTIVATED);
break;
}
case SCRIPT_COMMAND_RESPAWN: // 41
{
if (LogIfNotCreature(pTarget))
break;
((Creature*)pTarget)->Respawn();
break;
}
case SCRIPT_COMMAND_SET_EQUIPMENT_SLOTS: // 42
{
if (LogIfNotCreature(pSource))
return false;
Creature* pCSource = static_cast<Creature*>(pSource);
// reset default
if (m_script->setEquipment.resetDefault)
{
pCSource->LoadEquipment(pCSource->GetCreatureInfo()->EquipmentTemplateId, true);
break;
}
// main hand
if (m_script->textId[0] >= 0)
pCSource->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, m_script->textId[0]);
// off hand
if (m_script->textId[1] >= 0)
pCSource->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, m_script->textId[1]);
// ranged
if (m_script->textId[2] >= 0)
pCSource->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, m_script->textId[2]);
break;
}
case SCRIPT_COMMAND_RESET_GO: // 43
{
if (LogIfNotGameObject(pTarget))
break;
GameObject* pGoTarget = static_cast<GameObject*>(pTarget);
switch (pGoTarget->GetGoType())
{
case GAMEOBJECT_TYPE_DOOR:
case GAMEOBJECT_TYPE_BUTTON:
pGoTarget->ResetDoorOrButton();
break;
default:
sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u failed for gameobject(buddyEntry: %u). Gameobject is not a door or button", m_table, m_script->id, m_script->command, m_script->buddyEntry);
break;
}
break;
}
case SCRIPT_COMMAND_UPDATE_TEMPLATE: // 44
{
if (LogIfNotCreature(pSource))
return false;
Creature* pCSource = static_cast<Creature*>(pSource);
if (pCSource->GetEntry() != m_script->updateTemplate.newTemplate)
pCSource->UpdateEntry(m_script->updateTemplate.newTemplate, m_script->updateTemplate.newFactionTeam ? HORDE : ALLIANCE);
else
sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u failed. Source already has specified creature entry.", m_table, m_script->id, m_script->command);
break;
}
case SCRIPT_COMMAND_CHANGE_ENTRY: // 45
{
if (LogIfNotCreature(pSource))
{ break; }

View file

@ -132,7 +132,7 @@ enum DBScriptCommand // resSource, resTar
SCRIPT_COMMAND_XP_USER = 33, // source or target with Player, datalong = bool (0=off, 1=on)
SCRIPT_COMMAND_TERMINATE_COND = 34, // datalong = condition_id, datalong2 = if != 0 then quest_id of quest that will be failed for player's group if the script is terminated
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL terminate when condition is false ELSE terminate when condition is true
SCRIPT_COMMAND_SEND_AI_EVENT_AROUND = 35, // resSource = Creature, resTarget = Unit
SCRIPT_COMMAND_SEND_AI_EVENT = 35, // resSource = Creature, resTarget = Unit
// datalong = AIEventType
// datalong2 = radius
SCRIPT_COMMAND_TURN_TO = 36, // resSource = Unit, resTarget = Unit/none
@ -145,8 +145,20 @@ enum DBScriptCommand // resSource, resTar
SCRIPT_COMMAND_SEND_MAIL = 38, // resSource WorldObject, can be NULL, resTarget Player
// datalong: Send mailTemplateId from resSource (if provided) to player resTarget
// datalong2: AlternativeSenderEntry. Use as sender-Entry
SCRIPT_COMMAND_SET_FLY = 39, // resSource = Creature
// datalong = bool 0=off, 1=on
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL set/unset byte flag UNIT_BYTE1_FLAG_FLY_ANIM
// dataint1: Delay (>= 0) in Seconds
SCRIPT_COMMAND_CHANGE_ENTRY = 39, // resSource = Creature, datalong=creature entry
SCRIPT_COMMAND_DESPAWN_GO = 40, // resTarget = GameObject
SCRIPT_COMMAND_RESPAWN = 41, // resSource = Creature. Requires SCRIPT_FLAG_BUDDY_IS_DESPAWNED to find dead or despawned targets
SCRIPT_COMMAND_SET_EQUIPMENT_SLOTS = 42, // resSource = Creature
// datalong = resetDefault: bool 0=false, 1=true
// dataint = main hand slot; dataint2 = off hand slot; dataint3 = ranged slot
SCRIPT_COMMAND_RESET_GO = 43, // resTarget = GameObject
SCRIPT_COMMAND_UPDATE_TEMPLATE = 44, // resSource = Creature
// datalong = new Creature entry
// datalong2 = Alliance(0) Horde(1), other values throw error
SCRIPT_COMMAND_CHANGE_ENTRY = 45, // resSource = Creature, datalong=creature entry
// dataint1 = entry
};
@ -161,8 +173,9 @@ enum ScriptInfoDataFlags
SCRIPT_FLAG_COMMAND_ADDITIONAL = 0x08, // command dependend
SCRIPT_FLAG_BUDDY_BY_GUID = 0x10, // take the buddy by guid
SCRIPT_FLAG_BUDDY_IS_PET = 0x20, // buddy is a pet
SCRIPT_FLAG_BUDDY_IS_DESPAWNED = 0X40, // buddy is dead or despawned
};
#define MAX_SCRIPT_FLAG_VALID (2 * SCRIPT_FLAG_BUDDY_IS_PET - 1)
#define MAX_SCRIPT_FLAG_VALID (2 * SCRIPT_FLAG_BUDDY_IS_DESPAWNED - 1)
struct ScriptInfo
{
@ -371,7 +384,7 @@ struct ScriptInfo
uint32 failQuest; // datalong2
} terminateCond;
struct // SCRIPT_COMMAND_SEND_AI_EVENT_AROUND (35)
struct // SCRIPT_COMMAND_SEND_AI_EVENT (35)
{
uint32 eventType; // datalong
uint32 radius; // datalong2
@ -395,7 +408,30 @@ struct ScriptInfo
uint32 altSender; // datalong2;
} sendMail;
struct // SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL (23)
struct // SCRIPT_COMMAND_SET_FLY (39)
{
uint32 fly; // datalong
uint32 empty; // datalong2
} fly;
// datalong unsed // SCRIPT_COMMAND_DESPAWN_GO (40)
// datalong unsed // SCRIPT_COMMAND_RESPAWN (41)
struct // SCRIPT_COMMAND_SET_EQUIPMENT_SLOTS (42)
{
uint32 resetDefault; // datalong
uint32 empty; // datalong2
} setEquipment;
// datalong unsed // SCRIPT_COMMAND_RESET_GO (43)
struct // SCRIPT_COMMAND_UPDATE_TEMPLATE (44)
{
uint32 newTemplate; // datalong
uint32 newFactionTeam; // datalong2
} updateTemplate;
struct // SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL (45)
{
uint32 creatureEntry; // datalong
uint32 empty1; // datalong2
@ -443,6 +479,8 @@ struct ScriptInfo
case SCRIPT_COMMAND_CLOSE_DOOR:
case SCRIPT_COMMAND_ACTIVATE_OBJECT:
case SCRIPT_COMMAND_GO_LOCK_STATE:
case SCRIPT_COMMAND_DESPAWN_GO:
case SCRIPT_COMMAND_RESET_GO:
return false;
default:
return true;
@ -464,6 +502,7 @@ struct ScriptInfo
case SCRIPT_COMMAND_TERMINATE_COND:
case SCRIPT_COMMAND_TURN_TO:
case SCRIPT_COMMAND_MOVE_DYNAMIC:
case SCRIPT_COMMAND_SET_FLY:
return true;
default:
return false;

View file

@ -6154,24 +6154,29 @@ SpellCastResult Spell::CheckCast(bool strict)
case SPELL_EFFECT_LEAP:
case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER:
{
float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellEffect->GetRadiusIndex()));
float fx = m_caster->GetPositionX() + dis * cos(m_caster->GetOrientation());
float fy = m_caster->GetPositionY() + dis * sin(m_caster->GetOrientation());
// teleport a bit above terrain level to avoid falling below it
float fz = m_caster->GetMap()->GetHeight(m_caster->GetPhaseMask(), fx, fy, m_caster->GetPositionZ());
if (fz <= INVALID_HEIGHT) // note: this also will prevent use effect in instances without vmaps height enabled
return SPELL_FAILED_TRY_AGAIN;
if (!m_caster || m_caster->IsTaxiFlying())
return SPELL_FAILED_NOT_ON_TAXI;
float caster_pos_z = m_caster->GetPositionZ();
// Control the caster to not climb or drop when +-fz > 8
if (!(fz <= caster_pos_z + 8 && fz >= caster_pos_z - 8))
return SPELL_FAILED_TRY_AGAIN;
// Blink has leap first and then removing of auras with root effect
// need further research with this
SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(i));
if (!spellEffect)
break;
if (spellEffect->Effect != SPELL_EFFECT_LEAP)
{
if (m_caster->hasUnitState(UNIT_STAT_ROOT))
return SPELL_FAILED_ROOTED;
}
// not allow use this effect at battleground until battleground start
if (m_caster->GetTypeId() == TYPEID_PLAYER)
{
// not allow use this effect at battleground until battleground start
if (BattleGround const* bg = ((Player*)m_caster)->GetBattleGround())
if (bg->GetStatus() != STATUS_IN_PROGRESS)
return SPELL_FAILED_TRY_AGAIN;
}
break;
}
case SPELL_EFFECT_STEAL_BENEFICIAL_BUFF:

View file

@ -2976,7 +2976,7 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
{
//AreaTableEntry const* area = GetAreaEntryByAreaID(target->GetAreaId());
//// Dalaran restricted flight zone (recheck before apply unmount)
//// Dalaran restricstruct boss_freyted flight zone (recheck before apply unmount)
//if (area && target->GetTypeId() == TYPEID_PLAYER && (area->flags & AREA_FLAG_CANNOT_FLY) &&
// ((Player*)target)->IsFreeFlying() && !((Player*)target)->isGameMaster())
//{

View file

@ -5384,14 +5384,13 @@ void Spell::EffectSummonType(SpellEffectEntry const* effect)
if (summon_prop->Group == SUMMON_PROP_GROUP_PETS && prop_id != 1562)
{
DoSummonPet(effect);
return;
}
// Expected Amount: TODO - there are quite some exceptions (like totems, engineering dragonlings..)
uint32 amount = damage > 0 ? damage : 1;
// basepoints of SUMMON_PROP_GROUP_VEHICLE is often a spellId, set amount to 1
if (summon_prop->Group == SUMMON_PROP_GROUP_VEHICLE)
if (summon_prop->Group == SUMMON_PROP_GROUP_VEHICLE || summon_prop->Group == SUMMON_PROP_GROUP_UNCONTROLLABLE_VEHICLE || summon_prop->Group == SUMMON_PROP_GROUP_CONTROLLABLE)
amount = 1;
// Get casting object
@ -5552,6 +5551,7 @@ void Spell::EffectSummonType(SpellEffectEntry const* effect)
break;
}
case SUMMON_PROP_GROUP_VEHICLE:
case SUMMON_PROP_GROUP_UNCONTROLLABLE_VEHICLE:
{
summonResult = DoSummonVehicle(summonPositions, summon_prop, effect, level);
break;
@ -5750,17 +5750,30 @@ bool Spell::DoSummonGuardian(CreatureSummonPositions& list, SummonPropertiesEntr
if (m_duration > 0)
spawnCreature->SetDuration(m_duration);
CreatureInfo const* cInfo = spawnCreature->GetCreatureInfo();
// spawnCreature->SetName(""); // generated by client
spawnCreature->SetOwnerGuid(m_caster->GetObjectGuid());
spawnCreature->SetPowerType(POWER_MANA);
spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, spawnCreature->GetCreatureInfo()->NpcFlags);
spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, cInfo->UnitFlags);
spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, cInfo->NpcFlags);
spawnCreature->setFaction(m_caster->getFaction());
spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
spawnCreature->SetCreatorGuid(m_caster->GetObjectGuid());
spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
spawnCreature->InitStatsForLevel(level, m_caster);
spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
spawnCreature->InitStatsForLevel(level);
if (CharmInfo* charmInfo = spawnCreature->GetCharmInfo())
{
charmInfo->SetPetNumber(pet_number, false);
if (spawnCreature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE))
charmInfo->SetReactState(REACT_PASSIVE);
else if ((cInfo->ExtraFlags & CREATURE_EXTRA_FLAG_NO_MELEE) || petType == PROTECTOR_PET)
charmInfo->SetReactState(REACT_DEFENSIVE);
else
charmInfo->SetReactState(REACT_AGGRESSIVE);
}
m_caster->AddGuardian(spawnCreature);
}
@ -10721,24 +10734,159 @@ void Spell::EffectBlock(SpellEffectEntry const* /*effect*/)
void Spell::EffectLeapForward(SpellEffectEntry const* effect)
{
if (unitTarget->IsTaxiFlying())
return;
float dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->rangeIndex));
const float IN_OR_UNDER_LIQUID_RANGE = 0.8f; // range to make player under liquid or on liquid surface from liquid level
if (m_spellInfo->rangeIndex == SPELL_RANGE_IDX_SELF_ONLY)
G3D::Vector3 prevPos, nextPos;
float orientation = unitTarget->GetOrientation();
prevPos.x = unitTarget->GetPositionX();
prevPos.y = unitTarget->GetPositionY();
prevPos.z = unitTarget->GetPositionZ();
float groundZ = prevPos.z;
// falling case
if (!unitTarget->GetMap()->GetHeightInRange(unitTarget->GetPhaseMask(), prevPos.x, prevPos.y, groundZ, 3.0f) && unitTarget->m_movementInfo.HasMovementFlag(MOVEFLAG_FALLING))
{
float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(effect->GetRadiusIndex()));
nextPos.x = prevPos.x + dist * cos(orientation);
nextPos.y = prevPos.y + dist * sin(orientation);
nextPos.z = prevPos.z - 2.0f; // little hack to avoid the impression to go up when teleporting instead of continue to fall. This value may need some tweak
// before caster
float fx, fy, fz;
unitTarget->GetClosePoint(fx, fy, fz, unitTarget->GetObjectBoundingRadius(), dis);
float ox, oy, oz;
unitTarget->GetPosition(ox, oy, oz);
//
GridMapLiquidData liquidData;
if (unitTarget->GetMap()->GetTerrain()->IsInWater(nextPos.x, nextPos.y, nextPos.z, &liquidData))
{
if (fabs(nextPos.z - liquidData.level) < 10.0f)
nextPos.z = liquidData.level - IN_OR_UNDER_LIQUID_RANGE;
}
else
{
// fix z to ground if near of it
unitTarget->GetMap()->GetHeightInRange(unitTarget->GetPhaseMask(), nextPos.x, nextPos.y, nextPos.z, 10.0f);
}
if (unitTarget->GetMap()->GetHitPosition(ox, oy, oz + 0.5f, fx, fy, fz, unitTarget->GetPhaseMask(), -0.5f))
unitTarget->UpdateAllowedPositionZ(fx, fy, fz);
// check any obstacle and fix coords
unitTarget->GetMap()->GetHitPosition(prevPos.x, prevPos.y, prevPos.z + 0.5f, nextPos.x, nextPos.y, nextPos.z, unitTarget->GetPhaseMask(), -0.5f);
unitTarget->NearTeleportTo(fx, fy, fz, unitTarget->GetOrientation(), unitTarget == m_caster);
// teleport
unitTarget->NearTeleportTo(nextPos.x, nextPos.y, nextPos.z, orientation, unitTarget == m_caster);
//sLog.outString("Falling BLINK!");
return;
}
// fix origin position if player was jumping and near of the ground but not in ground
if (fabs(prevPos.z - groundZ) > 0.5f)
prevPos.z = groundZ;
//check if in liquid
bool isPrevInLiquid = unitTarget->GetMap()->GetTerrain()->IsInWater(prevPos.x, prevPos.y, prevPos.z);
const float step = 2.0f; // step length before next check slope/edge/water
const float maxSlope = 50.0f; // 50(degree) max seem best value for walkable slope
const float MAX_SLOPE_IN_RADIAN = maxSlope / 180.0f * M_PI_F;
float nextZPointEstimation = 1.0f;
float destx = prevPos.x + dist * cos(orientation);
float desty = prevPos.y + dist * sin(orientation);
const uint32 numChecks = ceil(fabs(dist / step));
const float DELTA_X = (destx - prevPos.x) / numChecks;
const float DELTA_Y = (desty - prevPos.y) / numChecks;
for (uint32 i = 1; i < numChecks + 1; ++i)
{
// compute next point average position
nextPos.x = prevPos.x + DELTA_X;
nextPos.y = prevPos.y + DELTA_Y;
nextPos.z = prevPos.z + nextZPointEstimation;
bool isInLiquid = false;
bool isInLiquidTested = false;
bool isOnGround = false;
GridMapLiquidData liquidData;
// try fix height for next position
if (!unitTarget->GetMap()->GetHeightInRange(unitTarget->GetPhaseMask(), nextPos.x, nextPos.y, nextPos.z))
{
// we cant so test if we are on water
if (!unitTarget->GetMap()->GetTerrain()->IsInWater(nextPos.x, nextPos.y, nextPos.z, &liquidData))
{
// not in water and cannot get correct height, maybe flying?
//sLog.outString("Can't get height of point %u, point value %s", i, nextPos.toString().c_str());
nextPos = prevPos;
break;
}
else
{
isInLiquid = true;
isInLiquidTested = true;
}
}
else
isOnGround = true; // player is on ground
if (isInLiquid || (!isInLiquidTested && unitTarget->GetMap()->GetTerrain()->IsInWater(nextPos.x, nextPos.y, nextPos.z, &liquidData)))
{
if (!isPrevInLiquid && fabs(liquidData.level - prevPos.z) > 2.0f)
{
// on edge of water with difference a bit to high to continue
//sLog.outString("Ground vs liquid edge detected!");
nextPos = prevPos;
break;
}
if ((liquidData.level - IN_OR_UNDER_LIQUID_RANGE) > nextPos.z)
nextPos.z = prevPos.z; // we are under water so next z equal prev z
else
nextPos.z = liquidData.level - IN_OR_UNDER_LIQUID_RANGE; // we are on water surface, so next z equal liquid level
isInLiquid = true;
float ground = nextPos.z;
if (unitTarget->GetMap()->GetHeightInRange(unitTarget->GetPhaseMask(), nextPos.x, nextPos.y, ground))
{
if (nextPos.z < ground)
{
nextPos.z = ground;
isOnGround = true; // player is on ground of the water
}
}
}
//unitTarget->SummonCreature(VISUAL_WAYPOINT, nextPos.x, nextPos.y, nextPos.z, 0, TEMPSUMMON_TIMED_DESPAWN, 15000);
float hitZ = nextPos.z + 1.5f;
if (unitTarget->GetMap()->GetHitPosition(prevPos.x, prevPos.y, prevPos.z + 1.5f, nextPos.x, nextPos.y, hitZ, unitTarget->GetPhaseMask(), -1.0f))
{
//sLog.outString("Blink collision detected!");
nextPos = prevPos;
break;
}
if (isOnGround)
{
// project vector to get only positive value
float ac = fabs(prevPos.z - nextPos.z);
// compute slope (in radian)
float slope = atan(ac / step);
// check slope value
if (slope > MAX_SLOPE_IN_RADIAN)
{
//sLog.outString("bad slope detected! %4.2f max %4.2f, ac(%4.2f)", slope * 180 / M_PI_F, maxSlope, ac);
nextPos = prevPos;
break;
}
//sLog.outString("slope is ok! %4.2f max %4.2f, ac(%4.2f)", slope * 180 / M_PI_F, maxSlope, ac);
}
//sLog.outString("point %u is ok, coords %s", i, nextPos.toString().c_str());
nextZPointEstimation = (nextPos.z - prevPos.z) / 2.0f;
isPrevInLiquid = isInLiquid;
prevPos = nextPos;
}
unitTarget->NearTeleportTo(nextPos.x, nextPos.y, nextPos.z, orientation, unitTarget == m_caster);
}
void Spell::EffectLeapBack(SpellEffectEntry const* effect)
@ -10922,11 +11070,18 @@ void Spell::EffectPlayerPull(SpellEffectEntry const* effect)
if (!unitTarget)
return;
float dist = unitTarget->GetDistance2d(m_caster);
if (damage && dist > damage)
dist = float(damage);
float x, y, z;
m_caster->GetPosition(x, y, z);
unitTarget->KnockBackFrom(m_caster, -dist, float(effect->EffectMiscValue) / 10);
// move back a bit
x = x - (0.6 * cos(m_caster->GetOrientation() + M_PI_F));
y = y - (0.6 * sin(m_caster->GetOrientation() + M_PI_F));
// Try to normalize Z coord because GetContactPoint do nothing with Z axis
unitTarget->UpdateAllowedPositionZ(x, y, z);
float speed = m_spellInfo->speed ? m_spellInfo->speed : 27.0f;
unitTarget->GetMotionMaster()->MoveJump(x, y, z, speed, 2.5f);
}
void Spell::EffectDispelMechanic(SpellEffectEntry const* effect)

View file

@ -293,10 +293,13 @@ void WorldSession::HandleGameObjectUseOpcode(WorldPacket& recv_data)
if (!_player->IsSelfMover())
return;
GameObject* obj = GetPlayer()->GetMap()->GetGameObject(guid);
GameObject* obj = _player->GetMap()->GetGameObject(guid);
if (!obj)
return;
if (!obj->IsWithinDistInMap(_player, obj->GetInteractionDistance()))
return;
// Additional check preventing exploits (ie loot despawned chests)
if (!obj->isSpawned())
{

View file

@ -635,6 +635,6 @@ void WaypointManager::CheckTextsExistance(std::set<int32>& ids)
{
for (WaypointPath::const_iterator pItr = pmItr->second.begin(); pItr != pmItr->second.end(); ++pItr)
if (pItr->second.behavior)
CheckWPText(false, pmItr->first, pItr->first, pItr->second.behavior, ids);
CheckWPText(true, pmItr->first, pItr->first, pItr->second.behavior, ids);
}
}

View file

@ -91,7 +91,7 @@ class WaypointManager
WaypointPath* GetDefaultPath(uint32 entry, uint32 lowGuid, WaypointPathOrigin* wpOrigin = NULL)
{
WaypointPath* path = NULL;
WaypointPath* path = GetPath(lowGuid);
path = GetPath(lowGuid);
if (path && wpOrigin)
*wpOrigin = PATH_FROM_GUID;

View file

@ -531,6 +531,7 @@ void World::LoadConfigSettings(bool reload)
setConfig(CONFIG_BOOL_ADDON_CHANNEL, "AddonChannel", true);
setConfig(CONFIG_BOOL_CLEAN_CHARACTER_DB, "CleanCharacterDB", true);
setConfig(CONFIG_BOOL_GRID_UNLOAD, "GridUnload", true);
setConfig(CONFIG_UINT32_MAX_WHOLIST_RETURNS, "MaxWhoListReturns", 49);
std::string forceLoadGridOnMaps = sConfig.GetStringDefault("LoadAllGridsOnMaps", "");
if (!forceLoadGridOnMaps.empty())

View file

@ -220,6 +220,8 @@ enum eConfigUInt32Values
CONFIG_UINT32_MIN_LEVEL_FOR_RAID,
CONFIG_UINT32_CREATURE_RESPAWN_AGGRO_DELAY,
CONFIG_UINT32_RANDOM_BG_RESET_HOUR,
CONFIG_UINT32_MAX_WHOLIST_RETURNS,
CONFIG_UINT32_VALUE_COUNT,
// Warden
CONFIG_UINT32_WARDEN_CLIENT_RESPONSE_DELAY,
CONFIG_UINT32_WARDEN_CLIENT_CHECK_HOLDOFF,
@ -227,8 +229,7 @@ enum eConfigUInt32Values
CONFIG_UINT32_WARDEN_CLIENT_BAN_DURATION,
CONFIG_UINT32_WARDEN_NUM_MEM_CHECKS,
CONFIG_UINT32_WARDEN_NUM_OTHER_CHECKS,
CONFIG_UINT32_WARDEN_DB_LOGLEVEL,
CONFIG_UINT32_VALUE_COUNT
CONFIG_UINT32_WARDEN_DB_LOGLEVEL
};
/// Configuration elements

View file

@ -43,11 +43,14 @@ enum
SPELL_MAGMASHACKLES = 19496,
SPELL_ERUPTION_TRIGGER = 20482, // target script, dispel and permanent immune to banish anywhere on map
SPELL_ENRAGE_TRIGGER = 19515, // target script, effect dummy anywhere on map
SPELL_ENRAGE = 19516,
// Add spells
SPELL_THRASH = 8876,
SPELL_IMMOLATE = 15733,
SPELL_ERUPTION = 19497,
SPELL_MASSIVE_ERUPTION = 20483, // TODO possible on death
SPELL_IMMOLATE = 20294,
SPELL_SEPARATION_ANXIETY_BOSSGARR = 23492, // Used if separated too far from Garr
};
struct boss_garr : public CreatureScript
@ -184,6 +187,10 @@ struct mob_firesworn : public CreatureScript
mob_fireswornAI(Creature* pCreature) : ScriptedAI(pCreature)
{
m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData();
Reset();
DoCastSpellIfCan(m_creature, SPELL_THRASH, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);
DoCastSpellIfCan(m_creature, SPELL_IMMOLATE, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);
}
ScriptedInstance* m_pInstance;
@ -199,6 +206,12 @@ struct mob_firesworn : public CreatureScript
m_bExploding = false;
}
void JustReachedHome() override
{
DoCastSpellIfCan(m_creature, SPELL_THRASH, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);
DoCastSpellIfCan(m_creature, SPELL_IMMOLATE, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);
}
void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override
{
if (!m_bExploding && m_creature->HealthBelowPctDamaged(10, uiDamage))

View file

@ -43,9 +43,11 @@ enum
SPELL_EARTHQUAKE = 19798,
SPELL_ENRAGE = 19953,
SPELL_GOLEMAGG_TRUST = 20553,
SPELL_DOUBLE_ATTACK = 18943,
// Core Rager
EMOTE_LOW_HP = -1409002,
SPELL_THRASH = 12787,
SPELL_MANGLE = 19820
};
@ -60,6 +62,7 @@ struct boss_golemagg : public CreatureScript
m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData();
#if defined (WOTLK) || defined (CATA)
DoCastSpellIfCan(m_creature, SPELL_MAGMA_SPLASH, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);
DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);
#endif
}
@ -185,6 +188,9 @@ struct mob_core_rager : public CreatureScript
mob_core_ragerAI(Creature* pCreature) : ScriptedAI(pCreature)
{
m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData();
Reset();
DoCastSpellIfCan(m_creature, SPELL_THRASH, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);
}
ScriptedInstance* m_pInstance;
@ -208,6 +214,11 @@ struct mob_core_rager : public CreatureScript
}
}
void JustReachedHome() override
{
DoCastSpellIfCan(m_creature, SPELL_THRASH, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);
}
void UpdateAI(const uint32 uiDiff) override
{
if (!m_creature->SelectHostileTarget() || !m_creature->getVictim())

View file

@ -43,6 +43,7 @@ enum
EMOTE_INSECT_SWARM = -1533154,
EMOTE_CORPSE_SCARABS = -1533155,
SPELL_DOUBLE_ATTACK = 18943,
SPELL_IMPALE = 28783, // May be wrong spell id. Causes more dmg than I expect
SPELL_IMPALE_H = 56090,
SPELL_LOCUSTSWARM = 28785, // This is a self buff that triggers the dmg debuff
@ -82,6 +83,9 @@ struct boss_anubrekhan : public CreatureScript
m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty();
m_introDialogue.InitializeDialogueHelper(m_pInstance);
m_bHasTaunted = false;
Reset();
DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);
}
ScriptedInstance* m_pInstance;
@ -135,6 +139,8 @@ struct boss_anubrekhan : public CreatureScript
{
if (m_pInstance)
m_pInstance->SetData(TYPE_ANUB_REKHAN, FAIL);
DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);
}
void MoveInLineOfSight(Unit* pWho) override

View file

@ -32,7 +32,8 @@ enum
EMOTE_ZOMBIE = -1533119,
EMOTE_BOSS_GENERIC_ENRAGED = -1000006,
EMOTE_DECIMATE = -1533152,
SPELL_DOUBLE_ATTACK = 19818,
SPELL_MORTALWOUND = 54378, // old vanilla spell was 25646,
SPELL_DECIMATE = 28374,
SPELL_DECIMATE_H = 54426,
@ -66,6 +67,9 @@ struct boss_gluth : public CreatureScript
{
m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData();
m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty();
Reset();
DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);
}
ScriptedInstance* m_pInstance;
@ -118,6 +122,8 @@ struct boss_gluth : public CreatureScript
{
if (m_pInstance)
m_pInstance->SetData(TYPE_GLUTH, FAIL);
DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);
}
void JustSummoned(Creature* pSummoned) override

View file

@ -34,6 +34,8 @@ enum
EMOTE_SPRAY = -1533148,
EMOTE_BOSS_GENERIC_FRENZY = -1000005,
SPELL_DOUBLE_ATTACK = 19818,
SPELL_WEBWRAP = 28622,
SPELL_WEBWRAP_2 = 28673, // purpose unknown
@ -166,6 +168,9 @@ struct boss_maexxna : public CreatureScript
{
m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData();
m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty();
Reset();
DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);
}
ScriptedInstance* m_pInstance;
@ -204,6 +209,8 @@ struct boss_maexxna : public CreatureScript
{
if (m_pInstance)
m_pInstance->SetData(TYPE_MAEXXNA, FAIL);
DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);
}
void JustSummoned(Creature* pSummoned) override

View file

@ -211,6 +211,7 @@ struct boss_freya : public CreatureScript
uint32 m_uiEpilogueTimer;
uint32 m_uiBerserkTimer;
uint32 m_uiDrainEldersTimer;
uint32 m_uiAlliesNatureTimer;
uint8 m_uiAlliesWaveCount;
@ -244,6 +245,7 @@ struct boss_freya : public CreatureScript
m_uiUnstableEnergyTimer = 0;
m_uiIronRootsTimer = 0;
m_uiGroundTremorTimer = 0;
m_uiDrainEldersTimer = 0;
// make the spawn spells random
std::random_shuffle(spawnSpellsVector.begin(), spawnSpellsVector.end());
@ -292,17 +294,26 @@ struct boss_freya : public CreatureScript
if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_BRIGHTLEAF))
{
if (pElder->IsAlive())
{
pElder->AI()->EnterEvadeMode();
pElder->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
}
if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_IRONBRACH))
{
if (pElder->IsAlive())
{
pElder->AI()->EnterEvadeMode();
pElder->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
}
if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_STONEBARK))
{
if (pElder->IsAlive())
{
pElder->AI()->EnterEvadeMode();
pElder->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
}
}
}
@ -468,7 +479,7 @@ struct boss_freya : public CreatureScript
{
if (pElder->IsAlive())
{
pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_BRIGHTLEAF_ESSENCE_CHANNEL : SPELL_BRIGHTLEAF_ESSENCE_CHANNEL_H, true);
pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_BRIGHTLEAF_ESSENCE_CHANNEL : SPELL_BRIGHTLEAF_ESSENCE_CHANNEL_H, false, NULL, NULL, m_creature->GetObjectGuid());
pElder->CastSpell(pElder, SPELL_FULL_HEAL, true);
m_uiUnstableEnergyTimer = 25000;
@ -479,7 +490,7 @@ struct boss_freya : public CreatureScript
{
if (pElder->IsAlive())
{
pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_IRONBRANCH_ESSENCE_CHANNEL : SPELL_IRONBRANCH_ESSENCE_CHANNEL_H, true);
pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_IRONBRANCH_ESSENCE_CHANNEL : SPELL_IRONBRANCH_ESSENCE_CHANNEL_H, false, NULL, NULL, m_creature->GetObjectGuid());
pElder->CastSpell(pElder, SPELL_FULL_HEAL, true);
m_uiIronRootsTimer = 60000;
@ -490,7 +501,7 @@ struct boss_freya : public CreatureScript
{
if (pElder->IsAlive())
{
pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_STONEBARK_ESSEMCE_CHANNEL : SPELL_STONEBARK_ESSEMCE_CHANNEL_H, true);
pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_STONEBARK_ESSEMCE_CHANNEL : SPELL_STONEBARK_ESSEMCE_CHANNEL_H, false, NULL, NULL, m_creature->GetObjectGuid());
pElder->CastSpell(pElder, SPELL_FULL_HEAL, true);
m_uiGroundTremorTimer = 10000;
@ -507,6 +518,38 @@ struct boss_freya : public CreatureScript
DoScriptText(SAY_AGGRO, m_creature);
}
// Function that will drain elders after aggro
void DoDrainElders()
{
if (!m_pInstance)
return;
if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_BRIGHTLEAF))
{
if (pElder->IsAlive())
{
pElder->CastSpell(pElder, SPELL_DRAINED_OF_POWER, true);
pElder->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
}
if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_IRONBRACH))
{
if (pElder->IsAlive())
{
pElder->CastSpell(pElder, SPELL_DRAINED_OF_POWER, true);
pElder->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
}
if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_STONEBARK))
{
if (pElder->IsAlive())
{
pElder->CastSpell(pElder, SPELL_DRAINED_OF_POWER, true);
pElder->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
}
}
void UpdateAI(const uint32 uiDiff) override
{
if (m_uiEpilogueTimer)
@ -540,6 +583,18 @@ struct boss_freya : public CreatureScript
m_uiBerserkTimer -= uiDiff;
}
// Drain elders after hard mode aggro
if (m_uiDrainEldersTimer)
{
if (m_uiDrainEldersTimer <= uiDiff)
{
DoDrainElders();
m_uiDrainEldersTimer = 0;
}
else
m_uiDrainEldersTimer -= uiDiff;
}
if (m_uiThreeAlliesTimer)
{
if (m_uiThreeAlliesTimer <= uiDiff)

View file

@ -44,9 +44,8 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
data=NULL;
}
FILE* f = fopen(filename, "rb");
if (!f)
{ return false; }
FILE * f = fopen(filename, "rb");
if(!f)return false;
if(fread(&header, 4, 1, f) != 1) // Signature
{
@ -59,10 +58,10 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
if(header != 0x32424457)
{
fclose(f);
return false;
return false; //'WDB2'
}
if (fread(&recordCount, 4, 1, f) != 1) // Number of records
if(fread(&recordCount,4,1,f)!=1) // Number of records
{
fclose(f);
return false;
@ -70,7 +69,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(recordCount);
if (fread(&fieldCount, 4, 1, f) != 1) // Number of fields
if(fread(&fieldCount,4,1,f)!=1) // Number of fields
{
fclose(f);
return false;
@ -78,7 +77,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(fieldCount);
if (fread(&recordSize, 4, 1, f) != 1) // Size of a record
if(fread(&recordSize,4,1,f)!=1) // Size of a record
{
fclose(f);
return false;
@ -86,7 +85,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(recordSize);
if (fread(&stringSize, 4, 1, f) != 1) // String size
if(fread(&stringSize,4,1,f)!=1) // String size
{
fclose(f);
return false;
@ -153,19 +152,19 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
fieldsOffset = new uint32[fieldCount];
fieldsOffset[0] = 0;
for (uint32 i = 1; i < fieldCount; ++i)
for(uint32 i = 1; i < fieldCount; i++)
{
fieldsOffset[i] = fieldsOffset[i - 1];
if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X') // byte fields
{ fieldsOffset[i] += 1; }
fieldsOffset[i] += 1;
else // 4 byte fields (int32/float/strings)
{ fieldsOffset[i] += 4; }
fieldsOffset[i] += 4;
}
data = new unsigned char[recordSize * recordCount + stringSize];
stringTable = data + recordSize * recordCount;
data = new unsigned char[recordSize*recordCount+stringSize];
stringTable = data + recordSize*recordCount;
if (fread(data, recordSize * recordCount + stringSize, 1, f) != 1)
if(fread(data, recordSize * recordCount + stringSize, 1, f) != 1)
{
fclose(f);
return false;