*Merged 459
--HG-- branch : trunk
This commit is contained in:
@@ -142,6 +142,7 @@ struct TRINITY_DLL_DECL Cell
|
||||
} data;
|
||||
|
||||
template<class LOCK_TYPE, class T, class CONTAINER> void Visit(const CellLock<LOCK_TYPE> &, TypeContainerVisitor<T, CONTAINER> &visitor, Map &) const;
|
||||
template<class LOCK_TYPE, class T, class CONTAINER> void Visit(const CellLock<LOCK_TYPE> &, TypeContainerVisitor<T, CONTAINER> &visitor, Map &, float radius, float x_off, float y_off) const;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
|
||||
@@ -129,4 +129,52 @@ Cell::Visit(const CellLock<LOCK_TYPE> &l, TypeContainerVisitor<T, CONTAINER> &vi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class LOCK_TYPE,class T, class CONTAINER>
|
||||
inline void
|
||||
Cell::Visit(const CellLock<LOCK_TYPE> &l, TypeContainerVisitor<T, CONTAINER> &visitor, Map &m, float radius, float x_off, float y_off) const
|
||||
{
|
||||
const CellPair &standing_cell = l.i_cellPair;
|
||||
if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
|
||||
return;
|
||||
|
||||
int left = 0, right = 0, upper = 0, lower = 0;
|
||||
|
||||
// Origin = (CENTER_GRID_CELL_OFFSET, CENTER_GRID_CELL_OFFSET)
|
||||
if(CENTER_GRID_CELL_OFFSET - x_off < radius)
|
||||
++right;
|
||||
if(CENTER_GRID_CELL_OFFSET + x_off < radius)
|
||||
++left;
|
||||
if(CENTER_GRID_CELL_OFFSET - y_off < radius)
|
||||
++upper;
|
||||
if(CENTER_GRID_CELL_OFFSET + y_off < radius)
|
||||
++lower;
|
||||
|
||||
if(!left && !right && !upper && !lower)
|
||||
{
|
||||
m.Visit(l, visitor);
|
||||
return;
|
||||
}
|
||||
|
||||
CellPair begin_cell = standing_cell;
|
||||
CellPair end_cell = standing_cell;
|
||||
|
||||
begin_cell << left; //note: need change << if left > 1
|
||||
begin_cell -= lower;
|
||||
end_cell >> right;
|
||||
end_cell += upper;
|
||||
|
||||
// loop the cell range
|
||||
for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; x++)
|
||||
{
|
||||
for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; y++)
|
||||
{
|
||||
CellPair cell_pair(x,y);
|
||||
Cell r_zone(cell_pair);
|
||||
r_zone.data.Part.nocreate = l->data.Part.nocreate;
|
||||
CellLock<LOCK_TYPE> lock(r_zone, cell_pair);
|
||||
m.Visit(lock, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+15
-7
@@ -137,13 +137,16 @@ ChatCommand * ChatHandler::getCommandTable()
|
||||
static ChatCommand wpCommandTable[] =
|
||||
{
|
||||
{ "show", SEC_GAMEMASTER, false, &ChatHandler::HandleWpShowCommand, "", NULL },
|
||||
{ "add", SEC_GAMEMASTER, false, &ChatHandler::HandleWpAddCommand, "", NULL },
|
||||
{ "modify", SEC_GAMEMASTER, false, &ChatHandler::HandleWpModifyCommand, "", NULL },
|
||||
{ "export", SEC_ADMINISTRATOR, false, &ChatHandler::HandleWpExportCommand, "", NULL },
|
||||
{ "import", SEC_ADMINISTRATOR, false, &ChatHandler::HandleWpImportCommand, "", NULL },
|
||||
{ NULL, 0, false, NULL, "", NULL }
|
||||
{ "addwp", SEC_GAMEMASTER, false, &ChatHandler::HandleWpAddCommand, "", NULL },
|
||||
{ "load", SEC_GAMEMASTER, false, &ChatHandler::HandleWpLoadPathCommand, "", NULL },
|
||||
{ "modify", SEC_GAMEMASTER, false, &ChatHandler::HandleWpModifyCommand, "", NULL },
|
||||
{ "event", SEC_GAMEMASTER, false, &ChatHandler::HandleWpEventCommand, "", NULL },
|
||||
{ "unload", SEC_GAMEMASTER, false, &ChatHandler::HandleWpUnLoadPathCommand, "", NULL },
|
||||
|
||||
{ NULL, 0, false, NULL, "", NULL }
|
||||
};
|
||||
|
||||
|
||||
static ChatCommand banCommandTable[] =
|
||||
{
|
||||
{ "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanAccountCommand, "", NULL },
|
||||
@@ -293,6 +296,7 @@ ChatCommand * ChatHandler::getCommandTable()
|
||||
{ "locales_npc_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesNpcTextCommand, "", NULL },
|
||||
{ "locales_page_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesPageTextCommand, "", NULL },
|
||||
{ "locales_quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesQuestCommand, "", NULL },
|
||||
{ "waypoint_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadWpScriptsCommand, "", NULL },
|
||||
|
||||
{ "", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCommand, "", NULL },
|
||||
{ NULL, 0, false, NULL, "", NULL }
|
||||
@@ -507,8 +511,12 @@ ChatCommand * ChatHandler::getCommandTable()
|
||||
{ "event", SEC_GAMEMASTER, false, NULL, "", eventCommandTable },
|
||||
{ "gobject", SEC_GAMEMASTER, false, NULL, "", gobjectCommandTable },
|
||||
{ "honor", SEC_GAMEMASTER, false, NULL, "", honorCommandTable },
|
||||
{ "wp", SEC_GAMEMASTER, false, NULL, "", wpCommandTable },
|
||||
{ "quest", SEC_ADMINISTRATOR, false, NULL, "", questCommandTable },
|
||||
|
||||
//wp commands
|
||||
{ "path", SEC_GAMEMASTER, false, NULL, "", wpCommandTable },
|
||||
{ "loadpath", SEC_ADMINISTRATOR, false, &ChatHandler::HandleReloadAllPaths, "", NULL },
|
||||
|
||||
{ "quest", SEC_ADMINISTRATOR, false, NULL, "", questCommandTable },
|
||||
{ "reload", SEC_ADMINISTRATOR, true, NULL, "", reloadCommandTable },
|
||||
{ "list", SEC_ADMINISTRATOR, true, NULL, "", listCommandTable },
|
||||
{ "lookup", SEC_ADMINISTRATOR, true, NULL, "", lookupCommandTable },
|
||||
|
||||
+12
-6
@@ -211,7 +211,8 @@ class ChatHandler
|
||||
|
||||
bool HandleReloadConfigCommand(const char* args);
|
||||
|
||||
bool HandleReloadAreaTriggerTavernCommand(const char* args);
|
||||
bool HandleReloadWpScriptsCommand(const char* args);
|
||||
bool HandleReloadAreaTriggerTavernCommand(const char* args);
|
||||
bool HandleReloadAreaTriggerTeleportCommand(const char* args);
|
||||
bool HandleReloadEventScriptsCommand(const char* args);
|
||||
bool HandleReloadCommandCommand(const char* args);
|
||||
@@ -410,11 +411,16 @@ class ChatHandler
|
||||
bool HandlePasswordCommand(const char* args);
|
||||
bool HandleLockAccountCommand(const char* args);
|
||||
bool HandleRespawnCommand(const char* args);
|
||||
bool HandleWpAddCommand(const char* args);
|
||||
bool HandleWpModifyCommand(const char* args);
|
||||
bool HandleWpShowCommand(const char* args);
|
||||
bool HandleWpExportCommand(const char* args);
|
||||
bool HandleWpImportCommand(const char* args);
|
||||
|
||||
//New Wp Commands
|
||||
bool HandleWpAddCommand(const char* args);
|
||||
bool HandleWpLoadPathCommand(const char* args);
|
||||
bool HandleWpUnLoadPathCommand(const char* args);
|
||||
bool HandleWpModifyCommand(const char* args);
|
||||
bool HandleWpEventCommand(const char* args);
|
||||
bool HandleWpShowCommand(const char* args);
|
||||
bool HandleReloadAllPaths(const char *args);
|
||||
|
||||
bool HandleFlyModeCommand(const char* args);
|
||||
bool HandleSendOpcodeCommand(const char* args);
|
||||
bool HandleSellErrorCommand(const char* args);
|
||||
|
||||
@@ -347,10 +347,10 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData *data )
|
||||
m_spells[3] = GetCreatureInfo()->spell4;
|
||||
|
||||
// HACK: trigger creature is always not selectable
|
||||
if(GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)
|
||||
if(isTrigger())
|
||||
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
|
||||
if(isTotem() || GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER
|
||||
if(isTotem() || isTrigger()
|
||||
|| GetCreatureType() == CREATURE_TYPE_CRITTER)
|
||||
SetReactState(REACT_PASSIVE);
|
||||
else if(isCivilian())
|
||||
@@ -563,7 +563,7 @@ void Creature::RegenerateHealth()
|
||||
ModifyHealth(addvalue);
|
||||
}
|
||||
|
||||
bool Creature::AIM_Initialize()
|
||||
bool Creature::AIM_Initialize(CreatureAI* ai)
|
||||
{
|
||||
// make sure nothing can change the AI during AI update
|
||||
if(m_AI_locked)
|
||||
@@ -578,7 +578,7 @@ bool Creature::AIM_Initialize()
|
||||
|
||||
CreatureAI * oldAI = i_AI;
|
||||
i_motionMaster.Initialize();
|
||||
i_AI = FactorySelector::selectAI(this);
|
||||
i_AI = ai ? ai : FactorySelector::selectAI(this);
|
||||
if (oldAI)
|
||||
delete oldAI;
|
||||
return true;
|
||||
@@ -2068,6 +2068,10 @@ bool Creature::LoadCreaturesAddon(bool reload)
|
||||
if (cainfo->move_flags != 0)
|
||||
SetUnitMovementFlags(cainfo->move_flags);
|
||||
|
||||
//Load Path
|
||||
if (cainfo->path_id != 0)
|
||||
m_path_id = cainfo->path_id;
|
||||
|
||||
if(cainfo->auras)
|
||||
{
|
||||
for (CreatureDataAddonAura const* cAura = cainfo->auras; cAura->spell_id; ++cAura)
|
||||
|
||||
+17
-4
@@ -279,7 +279,8 @@ struct CreatureDataAddonAura
|
||||
struct CreatureDataAddon
|
||||
{
|
||||
uint32 guidOrEntry;
|
||||
uint32 mount;
|
||||
uint32 path_id;
|
||||
uint32 mount;
|
||||
uint32 bytes0;
|
||||
uint32 bytes1;
|
||||
uint32 bytes2;
|
||||
@@ -425,6 +426,7 @@ class TRINITY_DLL_SPEC Creature : public Unit
|
||||
bool isTotem() const { return m_isTotem; }
|
||||
bool isRacialLeader() const { return GetCreatureInfo()->RacialLeader; }
|
||||
bool isCivilian() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN; }
|
||||
bool isTrigger() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER; }
|
||||
bool canWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; }
|
||||
bool canSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; }
|
||||
bool canFly() const { return GetCreatureInfo()->InhabitType & INHABIT_AIR; }
|
||||
@@ -461,7 +463,7 @@ class TRINITY_DLL_SPEC Creature : public Unit
|
||||
|
||||
bool IsInEvadeMode() const;
|
||||
|
||||
bool AIM_Initialize();
|
||||
bool AIM_Initialize(CreatureAI* ai = NULL);
|
||||
void InitPossessedAI();
|
||||
void DisablePossessedAI();
|
||||
|
||||
@@ -616,7 +618,14 @@ class TRINITY_DLL_SPEC Creature : public Unit
|
||||
void GetCombatStartPosition(float &x, float &y, float &z) { x = CombatStartX; y = CombatStartY; z = CombatStartZ; }
|
||||
|
||||
uint32 GetGlobalCooldown() const { return m_GlobalCooldown; }
|
||||
protected:
|
||||
|
||||
uint32 GetWaypointPath(){return m_path_id;}
|
||||
void LoadPath(uint32 pathid) { m_path_id = pathid; }
|
||||
|
||||
uint32 GetCurrentWaypointID(){return m_waypointID;}
|
||||
void UpdateWaypointID(uint32 wpID){m_waypointID = wpID;}
|
||||
|
||||
protected:
|
||||
bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL);
|
||||
bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL);
|
||||
|
||||
@@ -666,7 +675,11 @@ class TRINITY_DLL_SPEC Creature : public Unit
|
||||
float CombatStartZ;
|
||||
|
||||
private:
|
||||
GridReference<Creature> m_gridRef;
|
||||
//WaypointMovementGenerator vars
|
||||
uint32 m_waypointID;
|
||||
uint32 m_path_id;
|
||||
|
||||
GridReference<Creature> m_gridRef;
|
||||
CreatureInfo const* m_creatureInfo; // in heroic mode can different from ObjMgr::GetCreatureTemplate(GetEntry())
|
||||
};
|
||||
|
||||
|
||||
@@ -1277,7 +1277,7 @@ void GameObject::Use(Unit* user)
|
||||
void GameObject::CastSpell(Unit* target, uint32 spell)
|
||||
{
|
||||
//summon world trigger
|
||||
Creature *trigger = SummonCreature(12999, GetPositionX(), GetPositionY(), GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 1);
|
||||
Creature *trigger = SummonTrigger(GetPositionX(), GetPositionY(), GetPositionZ(), 0, 1);
|
||||
if(!trigger) return;
|
||||
|
||||
trigger->SetVisibility(VISIBILITY_OFF); //should this be true?
|
||||
|
||||
+23
-2
@@ -33,6 +33,17 @@ class GameObject;
|
||||
class Pet;
|
||||
class Player;
|
||||
|
||||
//comment the next line if CPU usage is too high
|
||||
#define LARGE_CELL
|
||||
|
||||
#ifdef LARGE_CELL
|
||||
#define MAX_NUMBER_OF_CELLS 4
|
||||
#define CENTER_GRID_CELL_ID 128
|
||||
#else
|
||||
#define MAX_NUMBER_OF_CELLS 8
|
||||
#define CENTER_GRID_CELL_ID 256
|
||||
#endif
|
||||
|
||||
#define MAX_NUMBER_OF_GRIDS 64
|
||||
|
||||
#define SIZE_OF_GRIDS 533.33333f
|
||||
@@ -43,10 +54,8 @@ class Player;
|
||||
#define MIN_GRID_DELAY MINUTE*1000
|
||||
#define MIN_MAP_UPDATE_DELAY 50
|
||||
|
||||
#define MAX_NUMBER_OF_CELLS 4
|
||||
#define SIZE_OF_GRID_CELL (SIZE_OF_GRIDS/MAX_NUMBER_OF_CELLS)
|
||||
|
||||
#define CENTER_GRID_CELL_ID 128
|
||||
#define CENTER_GRID_CELL_OFFSET (SIZE_OF_GRID_CELL/2)
|
||||
|
||||
#define TOTAL_NUMBER_OF_CELLS_PER_MAP (MAX_NUMBER_OF_GRIDS*MAX_NUMBER_OF_CELLS)
|
||||
@@ -141,6 +150,18 @@ namespace Trinity
|
||||
return Compute<CellPair, CENTER_GRID_CELL_ID>(x, y, CENTER_GRID_CELL_OFFSET, SIZE_OF_GRID_CELL);
|
||||
}
|
||||
|
||||
inline CellPair ComputeCellPair(float x, float y, float &x_off, float &y_off)
|
||||
{
|
||||
double x_offset = (double(x) - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL;
|
||||
double y_offset = (double(y) - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL;
|
||||
|
||||
int x_val = int(x_offset + 0.5);
|
||||
int y_val = int(y_offset + 0.5);
|
||||
x_off = (float(x_offset) - x_val) * SIZE_OF_GRID_CELL;
|
||||
y_off = (float(y_offset) - y_val) * SIZE_OF_GRID_CELL;
|
||||
return CellPair(x_val + CENTER_GRID_CELL_ID, y_val + CENTER_GRID_CELL_ID);
|
||||
}
|
||||
|
||||
inline void NormalizeMapCoord(float &c)
|
||||
{
|
||||
if(c > MAP_HALFSIZE - 0.5)
|
||||
|
||||
+675
-708
File diff suppressed because it is too large
Load Diff
+22
-1
@@ -136,7 +136,8 @@ bool ChatHandler::HandleReloadAllScriptsCommand(const char*)
|
||||
HandleReloadSpellScriptsCommand("a");
|
||||
SendGlobalSysMessage("DB tables `*_scripts` reloaded.");
|
||||
HandleReloadDbScriptStringCommand("a");
|
||||
return true;
|
||||
HandleReloadWpScriptsCommand("a");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleReloadAllSpellCommand(const char*)
|
||||
@@ -542,6 +543,26 @@ bool ChatHandler::HandleReloadEventScriptsCommand(const char* arg)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleReloadWpScriptsCommand(const char* arg)
|
||||
{
|
||||
if(sWorld.IsScriptScheduled())
|
||||
{
|
||||
SendSysMessage("DB scripts used currently, please attempt reload later.");
|
||||
SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(*arg!='a')
|
||||
sLog.outString( "Re-Loading Scripts from `event_scripts`...");
|
||||
|
||||
objmgr.LoadWaypointScripts();
|
||||
|
||||
if(*arg!='a')
|
||||
SendGlobalSysMessage("DB table `event_scripts` reloaded.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleReloadQuestEndScriptsCommand(const char* arg)
|
||||
{
|
||||
if(sWorld.IsScriptScheduled())
|
||||
|
||||
@@ -319,6 +319,31 @@ void MotionMaster::Mutate(MovementGenerator *m)
|
||||
push(m);
|
||||
}
|
||||
|
||||
void MotionMaster::MovePath(uint32 path_id, bool repeatable)
|
||||
{
|
||||
if(!path_id)
|
||||
return;
|
||||
//We set waypoint movement as new default movement generator
|
||||
// clear ALL movement generators (including default)
|
||||
while(!empty())
|
||||
{
|
||||
MovementGenerator *curr = top();
|
||||
curr->Finalize(*i_owner);
|
||||
pop();
|
||||
if( !isStatic( curr ) )
|
||||
delete curr;
|
||||
}
|
||||
|
||||
sLog.outError("attempting to move");
|
||||
//i_owner->GetTypeId()==TYPEID_PLAYER ?
|
||||
//Mutate(new WaypointMovementGenerator<Player>(path_id, repeatable)):
|
||||
Mutate(new WaypointMovementGenerator<Creature>(path_id, repeatable));
|
||||
|
||||
DEBUG_LOG("%s (GUID: %u) start moving over path(Id:%u, repeatable: %s)",
|
||||
i_owner->GetTypeId()==TYPEID_PLAYER ? "Player" : "Creature",
|
||||
i_owner->GetGUIDLow(), path_id, repeatable ? "YES" : "NO" );
|
||||
}
|
||||
|
||||
void MotionMaster::propagateSpeedChange()
|
||||
{
|
||||
Impl::container_type::iterator it = Impl::c.begin();
|
||||
|
||||
@@ -80,6 +80,7 @@ class TRINITY_DLL_SPEC MotionMaster : private std::stack<MovementGenerator *>
|
||||
void MovePoint(uint32 id, float x,float y,float z);
|
||||
void MoveTaxiFlight(uint32 path, uint32 pathnode);
|
||||
void MoveDistract(uint32 time);
|
||||
void MovePath(uint32 path_id, bool repeatable);
|
||||
|
||||
MovementGeneratorType GetCurrentMovementGeneratorType() const;
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ template<class MOVEMENT_GEN>
|
||||
inline MovementGenerator*
|
||||
MovementGeneratorFactory<MOVEMENT_GEN>::Create(void *data) const
|
||||
{
|
||||
Creature* creature = reinterpret_cast<Creature *>(data);
|
||||
return (new MOVEMENT_GEN(*creature));
|
||||
return (new MOVEMENT_GEN());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1534,6 +1534,25 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float
|
||||
return go;
|
||||
}
|
||||
|
||||
Creature* WorldObject::SummonTrigger(float x, float y, float z, float ang, uint32 duration, CreatureAI* (*GetAI)(Creature*))
|
||||
{
|
||||
TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
|
||||
Creature* summon = SummonCreature(WORLD_TRIGGER, x, y, z, ang, summonType, 0);
|
||||
if(!summon)
|
||||
return NULL;
|
||||
|
||||
//summon->SetName(GetName());
|
||||
if(GetTypeId()==TYPEID_PLAYER || GetTypeId()==TYPEID_UNIT)
|
||||
{
|
||||
summon->setFaction(((Unit*)this)->getFaction());
|
||||
summon->SetLevel(((Unit*)this)->getLevel());
|
||||
}
|
||||
|
||||
if(GetAI)
|
||||
summon->AIM_Initialize(GetAI(summon));
|
||||
return summon;
|
||||
}
|
||||
|
||||
void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float absAngle ) const
|
||||
{
|
||||
x = GetPositionX() + (GetObjectSize() + distance2d) * cos(absAngle);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "GameSystem/GridReference.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "GridDefines.h"
|
||||
#include "CreatureAI.h"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
@@ -457,6 +458,7 @@ class TRINITY_DLL_SPEC WorldObject : public Object
|
||||
Map const* GetBaseMap() const;
|
||||
Creature* SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime);
|
||||
GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime);
|
||||
Creature* SummonTrigger(float x, float y, float z, float ang, uint32 dur, CreatureAI* (*GetAI)(Creature*) = NULL);
|
||||
bool isActive() const { return m_isActive; }
|
||||
void setActive(bool isActive);
|
||||
protected:
|
||||
|
||||
+15
-1
@@ -54,6 +54,7 @@ ScriptMapMap sQuestStartScripts;
|
||||
ScriptMapMap sSpellScripts;
|
||||
ScriptMapMap sGameObjectScripts;
|
||||
ScriptMapMap sEventScripts;
|
||||
ScriptMapMap sWaypointScripts;
|
||||
|
||||
bool normalizePlayerName(std::string& name)
|
||||
{
|
||||
@@ -4110,6 +4111,19 @@ void ObjectMgr::LoadEventScripts()
|
||||
}
|
||||
}
|
||||
|
||||
//Load WP Scripts
|
||||
void ObjectMgr::LoadWaypointScripts()
|
||||
{
|
||||
LoadScripts(sWaypointScripts, "waypoint_scripts");
|
||||
|
||||
for(ScriptMapMap::const_iterator itr = sWaypointScripts.begin(); itr != sWaypointScripts.end(); ++itr)
|
||||
{
|
||||
QueryResult *query = WorldDatabase.PQuery("SELECT * FROM `waypoint_scripts` WHERE `id` = %u", itr->first);
|
||||
if(!query || !query->GetRowCount())
|
||||
sLog.outErrorDb("There is no waypoint which links to the waypoint script %u", itr->first);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadItemTexts()
|
||||
{
|
||||
QueryResult *result = CharacterDatabase.Query("SELECT id, text FROM item_text");
|
||||
@@ -7481,7 +7495,7 @@ void ObjectMgr::LoadDbScriptStrings()
|
||||
CheckScripts(sGameObjectScripts,ids);
|
||||
CheckScripts(sEventScripts,ids);
|
||||
|
||||
WaypointMgr.CheckTextsExistance(ids);
|
||||
CheckScripts(sWaypointScripts,ids);
|
||||
|
||||
for(std::set<int32>::const_iterator itr = ids.begin(); itr != ids.end(); ++itr)
|
||||
sLog.outErrorDb( "Table `db_script_string` has unused string id %u", *itr);
|
||||
|
||||
@@ -98,6 +98,7 @@ extern ScriptMapMap sQuestStartScripts;
|
||||
extern ScriptMapMap sSpellScripts;
|
||||
extern ScriptMapMap sGameObjectScripts;
|
||||
extern ScriptMapMap sEventScripts;
|
||||
extern ScriptMapMap sWaypointScripts;
|
||||
|
||||
struct AreaTrigger
|
||||
{
|
||||
@@ -531,6 +532,7 @@ class ObjectMgr
|
||||
void LoadQuestStartScripts();
|
||||
void LoadEventScripts();
|
||||
void LoadSpellScripts();
|
||||
void LoadWaypointScripts();
|
||||
|
||||
bool LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value);
|
||||
bool LoadTrinityStrings() { return LoadTrinityStrings(WorldDatabase,"trinity_string",MIN_TRINITY_STRING_ID,MAX_TRINITY_STRING_ID); }
|
||||
|
||||
+14
-3
@@ -1330,8 +1330,14 @@ void Player::setDeathState(DeathState s)
|
||||
|
||||
bool cur = isAlive();
|
||||
|
||||
if(s == JUST_DIED && cur)
|
||||
if(s == JUST_DIED)
|
||||
{
|
||||
if(!cur)
|
||||
{
|
||||
sLog.outError("setDeathState: attempt to kill a dead player %s(%d)", GetName(), GetGUIDLow());
|
||||
return;
|
||||
}
|
||||
|
||||
// drunken state is cleared on death
|
||||
SetDrunkValue(0);
|
||||
// lost combo points at any target (targeted combo points clear in Unit::setDeathState)
|
||||
@@ -13910,6 +13916,9 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
|
||||
m_movementInfo.t_o = 0.0f;
|
||||
}
|
||||
|
||||
if(!_LoadHomeBind(holder->GetResult(PLAYER_LOGIN_QUERY_LOADHOMEBIND)))
|
||||
return false;
|
||||
|
||||
// load the player's map here if it's not already loaded
|
||||
Map *map = GetMap();
|
||||
if (!map)
|
||||
@@ -13919,11 +13928,13 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
|
||||
{
|
||||
SetMapId(at->target_mapId);
|
||||
Relocate(at->target_X, at->target_Y, at->target_Z, GetOrientation());
|
||||
sLog.outError("Player (guidlow %d) is teleported to gobacktrigger (Map: %u X: %f Y: %f Z: %f O: %f).",guid,GetMapId(),GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetMapId(m_homebindMapId);
|
||||
Relocate(m_homebindX, m_homebindY, m_homebindZ, GetOrientation());
|
||||
sLog.outError("Player (guidlow %d) is teleported to home (Map: %u X: %f Y: %f Z: %f O: %f).",guid,GetMapId(),GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
|
||||
}
|
||||
|
||||
map = GetMap();
|
||||
@@ -14168,8 +14179,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
|
||||
|
||||
m_social = sSocialMgr.LoadFromDB(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSOCIALLIST), GetGUIDLow());
|
||||
|
||||
if(!_LoadHomeBind(holder->GetResult(PLAYER_LOGIN_QUERY_LOADHOMEBIND)))
|
||||
return false;
|
||||
//if(!_LoadHomeBind(holder->GetResult(PLAYER_LOGIN_QUERY_LOADHOMEBIND)))
|
||||
// return false;
|
||||
|
||||
// check PLAYER_CHOSEN_TITLE compatibility with PLAYER__FIELD_KNOWN_TITLES
|
||||
// note: PLAYER__FIELD_KNOWN_TITLES updated at quest status loaded
|
||||
|
||||
@@ -31,7 +31,7 @@ class TRINITY_DLL_SPEC RandomMovementGenerator
|
||||
: public MovementGeneratorMedium< T, RandomMovementGenerator<T> >
|
||||
{
|
||||
public:
|
||||
RandomMovementGenerator(const Unit &) : i_nextMoveTime(0) {}
|
||||
RandomMovementGenerator() : i_nextMoveTime(0) {}
|
||||
|
||||
void _setRandomLocation(T &);
|
||||
void Initialize(T &);
|
||||
|
||||
@@ -788,7 +788,7 @@ enum Targets
|
||||
TARGET_PET = 5,
|
||||
//TARGET_UNIT_PET
|
||||
TARGET_CHAIN_DAMAGE = 6,
|
||||
//TARGET_UNIT_TARGET_ENEMY
|
||||
TARGET_UNIT_TARGET_ENEMY = 6,
|
||||
TARGET_UNIT_AREA_ENTRY = 7,
|
||||
TARGET_AREAEFFECT_CUSTOM = 8,
|
||||
//TARGET_UNIT_AREA_ENTRY_GROUND
|
||||
@@ -806,7 +806,7 @@ enum Targets
|
||||
TARGET_ALL_PARTY_AROUND_CASTER = 20,
|
||||
//TARGET_UNIT_PARTY_CASTER
|
||||
TARGET_SINGLE_FRIEND = 21,
|
||||
//TARGET_UNIT_TARGET_ALLY
|
||||
TARGET_UNIT_TARGET_ALLY = 21,
|
||||
TARGET_ALL_AROUND_CASTER = 22, // used only in TargetA, target selection dependent from TargetB
|
||||
//TARGET_DEST_CASTER
|
||||
TARGET_GAMEOBJECT = 23,
|
||||
@@ -833,7 +833,7 @@ enum Targets
|
||||
TARGET_ALL_PARTY_AROUND_CASTER_2 = 34, // used in Tranquility
|
||||
//TARGET_UNIT_AREA_PARTY_GROUND
|
||||
TARGET_SINGLE_PARTY = 35,
|
||||
//TARGET_UNIT_TARGET_PARTY
|
||||
TARGET_UNIT_TARGET_PARTY = 35,
|
||||
TARGET_DEST_CASTER_RANDOM_UNKNOWN = 36, //unknown
|
||||
TARGET_AREAEFFECT_PARTY = 37,
|
||||
//TARGET_UNIT_PARTY_TARGET
|
||||
@@ -864,7 +864,7 @@ enum Targets
|
||||
TARGET_RANDOM_RAID_MEMBER = 56,
|
||||
//TARGET_UNIT_AREA_RAID
|
||||
TARGET_SINGLE_FRIEND_2 = 57,
|
||||
//TARGET_UNIT_TARGET_RAID
|
||||
TARGET_UNIT_TARGET_RAID = 57,
|
||||
TARGET_UNIT_CONE_ALLY = 59,
|
||||
TARGET_UNIT_AREA_SCRIPT = 60,
|
||||
TARGET_AREAEFFECT_PARTY_AND_CLASS = 61,
|
||||
@@ -908,6 +908,7 @@ enum SpellMissInfo
|
||||
SPELL_MISS_DEFLECT = 9,
|
||||
SPELL_MISS_ABSORB = 10,
|
||||
SPELL_MISS_REFLECT = 11,
|
||||
SPELL_MISS_KILL = 12, // kill grounding totem
|
||||
};
|
||||
|
||||
enum SpellHitType
|
||||
|
||||
+54
-40
@@ -286,8 +286,6 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
|
||||
m_caster = Caster;
|
||||
m_selfContainer = NULL;
|
||||
m_triggeringContainer = triggeringContainer;
|
||||
m_magnetPair.first = false;
|
||||
m_magnetPair.second = NULL;
|
||||
m_referencedFromCurrentSpell = false;
|
||||
m_executedCurrently = false;
|
||||
m_delayAtDamageCount = 0;
|
||||
@@ -1037,6 +1035,12 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
|
||||
if (target->reflectResult == SPELL_MISS_NONE) // If reflected spell hit caster -> do all effect on him
|
||||
DoSpellHitOnUnit(m_caster, mask);
|
||||
}
|
||||
else if (missInfo == SPELL_MISS_KILL)
|
||||
{
|
||||
// remove spell_magnet aura after first spell redirect and destroy target if its totem
|
||||
if(unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->isTotem())
|
||||
unit->Kill(unit);
|
||||
}
|
||||
else //TODO: This is a hack. need fix
|
||||
{
|
||||
uint32 tempMask = 0;
|
||||
@@ -1169,14 +1173,6 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
|
||||
if(!unit || !effectMask)
|
||||
return;
|
||||
|
||||
// remove spell_magnet aura after first spell redirect and destroy target if its totem
|
||||
if(m_magnetPair.first && m_magnetPair.second && m_magnetPair.second == unit)
|
||||
{
|
||||
if(unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->isTotem())
|
||||
unit->DealDamage(unit,unit->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Recheck immune (only for delayed spells)
|
||||
if( m_spellInfo->speed &&
|
||||
!(m_spellInfo->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY)
|
||||
@@ -1199,8 +1195,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
|
||||
}
|
||||
|
||||
unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_HITBYSPELL);
|
||||
//TODO: find a better way to judge CC auras
|
||||
if(m_spellInfo->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE)
|
||||
if(spellmgr.GetSpellCustomAttr(m_spellInfo->Id) & SPELL_ATTR_CU_AURA_CC)
|
||||
unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CC);
|
||||
}
|
||||
else
|
||||
@@ -1475,7 +1470,8 @@ void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, const u
|
||||
y = m_caster->GetPositionY();
|
||||
}
|
||||
|
||||
CellPair p(Trinity::ComputeCellPair(x, y));
|
||||
float x_off, y_off;
|
||||
CellPair p(Trinity::ComputeCellPair(x, y, x_off, y_off));
|
||||
Cell cell(p);
|
||||
cell.data.Part.reserved = ALL_DISTRICT;
|
||||
cell.SetNoCreate();
|
||||
@@ -1486,12 +1482,12 @@ void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, const u
|
||||
//if(TargetType != SPELL_TARGETS_ENTRY)
|
||||
{
|
||||
TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier);
|
||||
cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
|
||||
cell_lock->Visit(cell_lock, world_object_notifier, *m_caster->GetMap(), radius, x_off, y_off);
|
||||
}
|
||||
if(!(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY))
|
||||
{
|
||||
TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_object_notifier(notifier);
|
||||
cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
|
||||
cell_lock->Visit(cell_lock, grid_object_notifier, *m_caster->GetMap(), radius, x_off, y_off);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4501,26 +4497,8 @@ int16 Spell::PetCanCast(Unit* target)
|
||||
if(!_target->isAlive())
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
if(IsPositiveSpell(m_spellInfo->Id))
|
||||
{
|
||||
if(m_caster->IsHostileTo(_target))
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool duelvsplayertar = false;
|
||||
for(int j=0;j<3;j++)
|
||||
{
|
||||
//TARGET_DUELVSPLAYER is positive AND negative
|
||||
duelvsplayertar |= (m_spellInfo->EffectImplicitTargetA[j] == TARGET_DUELVSPLAYER);
|
||||
}
|
||||
// AoE spells have the caster as their target
|
||||
// AOE spells should not have target
|
||||
if(m_caster->IsFriendlyTo(target) /*&& m_caster != target*/ && !duelvsplayertar)
|
||||
{
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
}
|
||||
if(!IsValidSingleTargetSpell(_target))
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
//cooldown
|
||||
if(((Creature*)m_caster)->HasSpellCooldown(m_spellInfo->Id))
|
||||
@@ -5311,7 +5289,7 @@ CurrentSpellTypes Spell::GetCurrentContainer()
|
||||
bool Spell::CheckTarget( Unit* target, uint32 eff, bool hitPhase )
|
||||
{
|
||||
// Check targets for creature type mask and remove not appropriate (skip explicit self target case, maybe need other explicit targets)
|
||||
if(m_spellInfo->EffectImplicitTargetA[eff]!=TARGET_SELF && !m_magnetPair.first)
|
||||
if(m_spellInfo->EffectImplicitTargetA[eff]!=TARGET_SELF)
|
||||
{
|
||||
if (!CheckTargetCreatureType(target))
|
||||
return false;
|
||||
@@ -5392,14 +5370,21 @@ Unit* Spell::SelectMagnetTarget()
|
||||
{
|
||||
if(Unit* magnet = (*itr)->GetCaster())
|
||||
{
|
||||
if((*itr)->m_procCharges>0 && magnet->IsWithinLOSInMap(m_caster))
|
||||
if((*itr)->m_procCharges>0)
|
||||
{
|
||||
(*itr)->SetAuraProcCharges((*itr)->m_procCharges-1);
|
||||
m_magnetPair.first = true;
|
||||
m_magnetPair.second = magnet;
|
||||
|
||||
target = magnet;
|
||||
m_targets.setUnitTarget(target);
|
||||
AddUnitTarget(target, 0);
|
||||
uint64 targetGUID = target->GetGUID();
|
||||
for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
|
||||
{
|
||||
if (targetGUID == ihit->targetGUID) // Found in list
|
||||
{
|
||||
(*ihit).missCondition = SPELL_MISS_KILL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -5551,3 +5536,32 @@ bool SpellEvent::IsDeletable() const
|
||||
{
|
||||
return m_Spell->IsDeletable();
|
||||
}
|
||||
|
||||
bool Spell::IsValidSingleTargetEffect(Unit const* target, Targets type) const
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case TARGET_UNIT_TARGET_ENEMY:
|
||||
return !m_caster->IsFriendlyTo(target);
|
||||
case TARGET_UNIT_TARGET_ALLY:
|
||||
return m_caster->IsFriendlyTo(target);
|
||||
case TARGET_UNIT_TARGET_PARTY:
|
||||
return m_caster->IsInPartyWith(target);
|
||||
case TARGET_UNIT_TARGET_RAID:
|
||||
return m_caster->IsInRaidWith(target);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Spell::IsValidSingleTargetSpell(Unit const* target) const
|
||||
{
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
if(!IsValidSingleTargetEffect(target, Targets(m_spellInfo->EffectImplicitTargetA[i])))
|
||||
return false;
|
||||
// Need to check B?
|
||||
//if(!IsValidSingleTargetEffect(m_spellInfo->EffectImplicitTargetB[i], target)
|
||||
// return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
+2
-1
@@ -364,7 +364,6 @@ class Spell
|
||||
void SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap);
|
||||
|
||||
Unit* SelectMagnetTarget();
|
||||
std::pair <bool,Unit *> m_magnetPair;
|
||||
bool CheckTarget( Unit* target, uint32 eff, bool hitPhase );
|
||||
|
||||
void SendCastResult(uint8 result);
|
||||
@@ -538,6 +537,8 @@ class Spell
|
||||
SpellTargets TargetType, uint32 entry = 0);
|
||||
Unit* SearchNearbyTarget(float radius, SpellTargets TargetType, uint32 entry = 0);
|
||||
void SearchChainTarget(std::list<Unit*> &data, Unit* pUnitTarget, float max_range, uint32 unMaxTargets);
|
||||
bool IsValidSingleTargetEffect(Unit const* target, Targets type) const;
|
||||
bool IsValidSingleTargetSpell(Unit const* target) const;
|
||||
// -------------------------------------------
|
||||
|
||||
//List For Triggered Spells
|
||||
|
||||
+16
-93
@@ -2079,6 +2079,13 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// electrical storm safe zone
|
||||
if (GetId() == 44007)
|
||||
{
|
||||
m_target->ApplySpellImmune(44007, IMMUNITY_ID, 43657, apply);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPELLFAMILY_MAGE:
|
||||
@@ -3040,7 +3047,8 @@ void Aura::HandleModConfuse(bool apply, bool Real)
|
||||
if(!Real)
|
||||
return;
|
||||
|
||||
m_target->SetConfused(apply, GetCasterGUID(), GetId());
|
||||
//m_target->SetConfused(apply, GetCasterGUID(), GetId());
|
||||
m_target->SetControlled(apply, UNIT_STAT_CONFUSED);
|
||||
}
|
||||
|
||||
void Aura::HandleModFear(bool apply, bool Real)
|
||||
@@ -3048,7 +3056,8 @@ void Aura::HandleModFear(bool apply, bool Real)
|
||||
if (!Real)
|
||||
return;
|
||||
|
||||
m_target->SetFeared(apply, GetCasterGUID(), GetId());
|
||||
//m_target->SetFeared(apply, GetCasterGUID(), GetId());
|
||||
m_target->SetControlled(apply, UNIT_STAT_FLEEING);
|
||||
}
|
||||
|
||||
void Aura::HandleFeignDeath(bool apply, bool Real)
|
||||
@@ -3146,46 +3155,7 @@ void Aura::HandleAuraModStun(bool apply, bool Real)
|
||||
if(!Real)
|
||||
return;
|
||||
|
||||
if (apply)
|
||||
{
|
||||
m_target->addUnitState(UNIT_STAT_STUNNED);
|
||||
m_target->SetUInt64Value(UNIT_FIELD_TARGET, 0);
|
||||
|
||||
m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
|
||||
m_target->CastStop(m_target->GetGUID() == GetCasterGUID() ? GetId() : 0);
|
||||
|
||||
// Creature specific
|
||||
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
||||
((Creature*)m_target)->StopMoving();
|
||||
else
|
||||
m_target->SetUnitMovementFlags(0); //Clear movement flags
|
||||
|
||||
WorldPacket data(SMSG_FORCE_MOVE_ROOT, 8);
|
||||
|
||||
data.append(m_target->GetPackGUID());
|
||||
data << uint32(0);
|
||||
m_target->SendMessageToSet(&data,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Real remove called after current aura remove from lists, check if other similar auras active
|
||||
if(m_target->HasAuraType(SPELL_AURA_MOD_STUN))
|
||||
return;
|
||||
|
||||
m_target->clearUnitState(UNIT_STAT_STUNNED);
|
||||
m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
|
||||
|
||||
if(!m_target->hasUnitState(UNIT_STAT_ROOT)) // prevent allow move if have also root effect
|
||||
{
|
||||
if(m_target->getVictim() && m_target->isAlive())
|
||||
m_target->SetUInt64Value(UNIT_FIELD_TARGET,m_target->getVictim()->GetGUID() );
|
||||
|
||||
WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 8+4);
|
||||
data.append(m_target->GetPackGUID());
|
||||
data << uint32(0);
|
||||
m_target->SendMessageToSet(&data,true);
|
||||
}
|
||||
}
|
||||
m_target->SetControlled(apply, UNIT_STAT_STUNNED);
|
||||
}
|
||||
|
||||
void Aura::HandleModStealth(bool apply, bool Real)
|
||||
@@ -3355,55 +3325,7 @@ void Aura::HandleAuraModRoot(bool apply, bool Real)
|
||||
if(!Real)
|
||||
return;
|
||||
|
||||
uint32 apply_stat = UNIT_STAT_ROOT;
|
||||
if (apply)
|
||||
{
|
||||
m_target->addUnitState(UNIT_STAT_ROOT);
|
||||
m_target->SetUInt64Value (UNIT_FIELD_TARGET, 0);
|
||||
// probably wrong
|
||||
m_target->SetFlag(UNIT_FIELD_FLAGS,(apply_stat<<16));
|
||||
|
||||
//Save last orientation
|
||||
if( m_target->getVictim() )
|
||||
m_target->SetOrientation(m_target->GetAngle(m_target->getVictim()));
|
||||
|
||||
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10);
|
||||
data.append(m_target->GetPackGUID());
|
||||
data << (uint32)2;
|
||||
m_target->SendMessageToSet(&data,true);
|
||||
|
||||
//Clear unit movement flags
|
||||
m_target->SetUnitMovementFlags(0);
|
||||
}
|
||||
else
|
||||
((Creature *)m_target)->StopMoving();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Real remove called after current aura remove from lists, check if other similar auras active
|
||||
if(m_target->HasAuraType(SPELL_AURA_MOD_ROOT))
|
||||
return;
|
||||
|
||||
m_target->clearUnitState(UNIT_STAT_ROOT);
|
||||
// probably wrong
|
||||
m_target->RemoveFlag(UNIT_FIELD_FLAGS,(apply_stat<<16));
|
||||
|
||||
if(!m_target->hasUnitState(UNIT_STAT_STUNNED)) // prevent allow move if have also stun effect
|
||||
{
|
||||
if(m_target->getVictim() && m_target->isAlive())
|
||||
m_target->SetUInt64Value (UNIT_FIELD_TARGET,m_target->getVictim()->GetGUID() );
|
||||
|
||||
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 10);
|
||||
data.append(m_target->GetPackGUID());
|
||||
data << (uint32)2;
|
||||
m_target->SendMessageToSet(&data,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_target->SetControlled(apply, UNIT_STAT_ROOT);
|
||||
}
|
||||
|
||||
void Aura::HandleAuraModSilence(bool apply, bool Real)
|
||||
@@ -6231,10 +6153,11 @@ void Aura::HandlePreventFleeing(bool apply, bool Real)
|
||||
Unit::AuraList const& fearAuras = m_target->GetAurasByType(SPELL_AURA_MOD_FEAR);
|
||||
if( !fearAuras.empty() )
|
||||
{
|
||||
if (apply)
|
||||
m_target->SetControlled(!apply, UNIT_STAT_FLEEING);
|
||||
/*if (apply)
|
||||
m_target->SetFeared(false, fearAuras.front()->GetCasterGUID());
|
||||
else
|
||||
m_target->SetFeared(true);
|
||||
m_target->SetFeared(true);*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+21
-12
@@ -1824,27 +1824,36 @@ void SpellMgr::LoadSpellPetAuras()
|
||||
// set data in core for now
|
||||
void SpellMgr::LoadSpellCustomAttr()
|
||||
{
|
||||
mSpellCustomAttr.resize(GetSpellStore()->GetNumRows());
|
||||
|
||||
SpellEntry *tempSpell;
|
||||
for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i)
|
||||
{
|
||||
mSpellCustomAttr[i] = 0;
|
||||
tempSpell = (SpellEntry*)GetSpellStore()->LookupEntry(i);
|
||||
if(!tempSpell)
|
||||
continue;
|
||||
|
||||
mSpellCustomAttrMap[tempSpell->Id] = 0;
|
||||
|
||||
for(uint32 i = 0; i < 3; ++i)
|
||||
for(uint32 j = 0; j < 3; ++j)
|
||||
{
|
||||
switch(tempSpell->EffectApplyAuraName[i])
|
||||
switch(tempSpell->EffectApplyAuraName[j])
|
||||
{
|
||||
case SPELL_AURA_PERIODIC_DAMAGE:
|
||||
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
|
||||
case SPELL_AURA_PERIODIC_LEECH:
|
||||
mSpellCustomAttrMap[tempSpell->Id] |= SPELL_ATTR_CU_EFFECT_DAMAGE;
|
||||
mSpellCustomAttr[i] |= SPELL_ATTR_CU_AURA_DOT;
|
||||
break;
|
||||
case SPELL_AURA_PERIODIC_HEAL:
|
||||
case SPELL_AURA_OBS_MOD_HEALTH:
|
||||
mSpellCustomAttrMap[tempSpell->Id] |= SPELL_ATTR_CU_EFFECT_HEAL;
|
||||
mSpellCustomAttr[i] |= SPELL_ATTR_CU_AURA_HOT;
|
||||
break;
|
||||
case SPELL_AURA_MOD_POSSESS:
|
||||
case SPELL_AURA_MOD_CONFUSE:
|
||||
case SPELL_AURA_MOD_CHARM:
|
||||
case SPELL_AURA_MOD_FEAR:
|
||||
case SPELL_AURA_MOD_STUN:
|
||||
case SPELL_AURA_MOD_ROOT:
|
||||
mSpellCustomAttr[i] |= SPELL_ATTR_CU_AURA_CC;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -1852,14 +1861,14 @@ void SpellMgr::LoadSpellCustomAttr()
|
||||
}
|
||||
|
||||
if(tempSpell->SpellVisual == 3879)
|
||||
mSpellCustomAttrMap[tempSpell->Id] |= SPELL_ATTR_CU_CONE_BACK;
|
||||
mSpellCustomAttr[i] |= SPELL_ATTR_CU_CONE_BACK;
|
||||
|
||||
switch(tempSpell->Id)
|
||||
switch(i)
|
||||
{
|
||||
case 26029: // dark glare
|
||||
case 37433: // spout
|
||||
case 43140: case 43215: // flame breath
|
||||
mSpellCustomAttrMap[tempSpell->Id] |= SPELL_ATTR_CU_CONE_LINE;
|
||||
mSpellCustomAttr[i] |= SPELL_ATTR_CU_CONE_LINE;
|
||||
break;
|
||||
case 24340: case 26558: case 28884: // Meteor
|
||||
case 36837: case 38903: case 41276: // Meteor
|
||||
@@ -1869,7 +1878,7 @@ void SpellMgr::LoadSpellCustomAttr()
|
||||
case 40810: case 43267: case 43268: // Saber Lash
|
||||
case 42384: // Brutal Swipe
|
||||
case 45150: // Meteor Slash
|
||||
mSpellCustomAttrMap[tempSpell->Id] |= SPELL_ATTR_CU_SHARE_DAMAGE;
|
||||
mSpellCustomAttr[i] |= SPELL_ATTR_CU_SHARE_DAMAGE;
|
||||
break;
|
||||
case 44978: case 45001: case 45002: // Wild Magic
|
||||
case 45004: case 45006: case 45010: // Wild Magic
|
||||
@@ -1878,12 +1887,12 @@ void SpellMgr::LoadSpellCustomAttr()
|
||||
case 44869: // Spectral Blast
|
||||
case 45027: // Revitalize
|
||||
case 45976: // Muru Portal Channel
|
||||
mSpellCustomAttrMap[tempSpell->Id] |= SPELL_ATTR_CU_PLAYERS_ONLY;
|
||||
mSpellCustomAttr[i] |= SPELL_ATTR_CU_PLAYERS_ONLY;
|
||||
tempSpell->MaxAffectedTargets = 1;
|
||||
break;
|
||||
case 41376: // Spite
|
||||
case 39992: // Needle Spine
|
||||
mSpellCustomAttrMap[tempSpell->Id] |= SPELL_ATTR_CU_PLAYERS_ONLY;
|
||||
mSpellCustomAttr[i] |= SPELL_ATTR_CU_PLAYERS_ONLY;
|
||||
tempSpell->MaxAffectedTargets = 3;
|
||||
break;
|
||||
case 8122: case 8124: case 10888: case 10890: // Psychic Scream
|
||||
|
||||
+11
-6
@@ -681,10 +681,11 @@ inline bool IsProfessionSkill(uint32 skill)
|
||||
#define SPELL_ATTR_CU_CONE_BACK 0x00000002
|
||||
#define SPELL_ATTR_CU_CONE_LINE 0x00000004
|
||||
#define SPELL_ATTR_CU_SHARE_DAMAGE 0x00000008
|
||||
#define SPELL_ATTR_CU_EFFECT_HEAL 0x00000010
|
||||
#define SPELL_ATTR_CU_EFFECT_DAMAGE 0x00000020
|
||||
#define SPELL_ATTR_CU_AURA_HOT 0x00000010
|
||||
#define SPELL_ATTR_CU_AURA_DOT 0x00000020
|
||||
#define SPELL_ATTR_CU_AURA_CC 0x00000040
|
||||
|
||||
typedef std::map<uint32, uint32> SpellCustomAttrMap;
|
||||
typedef std::vector<uint32> SpellCustomAttribute;
|
||||
|
||||
typedef std::map<int32, std::vector<int32> > SpellLinkedMap;
|
||||
|
||||
@@ -888,11 +889,15 @@ class SpellMgr
|
||||
|
||||
uint32 GetSpellCustomAttr(uint32 spell_id) const
|
||||
{
|
||||
SpellCustomAttrMap::const_iterator itr = mSpellCustomAttrMap.find(spell_id);
|
||||
if(spell_id >= mSpellCustomAttr.size())
|
||||
return 0;
|
||||
else
|
||||
return mSpellCustomAttr[spell_id];
|
||||
/*SpellCustomAttrMap::const_iterator itr = mSpellCustomAttrMap.find(spell_id);
|
||||
if(itr != mSpellCustomAttrMap.end())
|
||||
return itr->second;
|
||||
else
|
||||
return 0;
|
||||
return 0;*/
|
||||
}
|
||||
|
||||
const std::vector<int32> *GetSpellLinked(int32 spell_id) const
|
||||
@@ -932,7 +937,7 @@ class SpellMgr
|
||||
SpellProcEventMap mSpellProcEventMap;
|
||||
SkillLineAbilityMap mSkillLineAbilityMap;
|
||||
SpellPetAuraMap mSpellPetAuraMap;
|
||||
SpellCustomAttrMap mSpellCustomAttrMap;
|
||||
SpellCustomAttribute mSpellCustomAttr;
|
||||
SpellLinkedMap mSpellLinkedMap;
|
||||
};
|
||||
|
||||
|
||||
+222
-14
@@ -862,15 +862,15 @@ void Unit::CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, I
|
||||
|
||||
SpellCastTargets targets;
|
||||
uint32 targetMask = spellInfo->Targets;
|
||||
if(targetMask & (TARGET_FLAG_UNIT|TARGET_FLAG_UNK2))
|
||||
targets.setUnitTarget(Victim);
|
||||
/*if(targetMask & (TARGET_FLAG_UNIT|TARGET_FLAG_UNK2))
|
||||
{
|
||||
if(!Victim)
|
||||
{
|
||||
sLog.outError("CastSpell: spell id %i by caster: %s %u) does not have unit target", spellInfo->Id,(GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
|
||||
return;
|
||||
}
|
||||
targets.setUnitTarget(Victim);
|
||||
}
|
||||
}*/
|
||||
if(targetMask & (TARGET_FLAG_SOURCE_LOCATION|TARGET_FLAG_DEST_LOCATION))
|
||||
{
|
||||
if(!Victim)
|
||||
@@ -916,15 +916,15 @@ void Unit::CastCustomSpell(Unit* Victim,SpellEntry const *spellInfo, int32 const
|
||||
|
||||
SpellCastTargets targets;
|
||||
uint32 targetMask = spellInfo->Targets;
|
||||
if(targetMask & (TARGET_FLAG_UNIT|TARGET_FLAG_UNK2))
|
||||
targets.setUnitTarget(Victim);
|
||||
/*if(targetMask & (TARGET_FLAG_UNIT|TARGET_FLAG_UNK2))
|
||||
{
|
||||
if(!Victim)
|
||||
{
|
||||
sLog.outError("CastCustomSpell: spell id %i by caster: %s %u) does not have unit target", spellInfo->Id,(GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
|
||||
return;
|
||||
}
|
||||
targets.setUnitTarget(Victim);
|
||||
}
|
||||
}*/
|
||||
if(targetMask & (TARGET_FLAG_SOURCE_LOCATION|TARGET_FLAG_DEST_LOCATION))
|
||||
{
|
||||
if(!Victim)
|
||||
@@ -8303,7 +8303,7 @@ Unit *Unit::GetCharmer() const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Player* Unit::GetCharmerOrOwnerPlayerOrPlayerItself()
|
||||
Player* Unit::GetCharmerOrOwnerPlayerOrPlayerItself() const
|
||||
{
|
||||
uint64 guid = GetCharmerOrOwnerGUID();
|
||||
if(IS_PLAYER_GUID(guid))
|
||||
@@ -9271,13 +9271,6 @@ bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
|
||||
if (!spellInfo)
|
||||
return false;
|
||||
|
||||
//FIX ME this hack: don't get feared if stunned
|
||||
if (spellInfo->Mechanic == MECHANIC_FEAR )
|
||||
{
|
||||
if ( hasUnitState(UNIT_STAT_STUNNED) )
|
||||
return true;
|
||||
}
|
||||
|
||||
SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
|
||||
for(SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
|
||||
if(itr->type == spellInfo->Dispel)
|
||||
@@ -11855,6 +11848,7 @@ void Unit::StopMoving()
|
||||
SendMessageToSet(&data,false);
|
||||
}
|
||||
|
||||
/*
|
||||
void Unit::SetFeared(bool apply, uint64 casterGUID, uint32 spellID)
|
||||
{
|
||||
if( apply )
|
||||
@@ -11923,6 +11917,7 @@ void Unit::SetConfused(bool apply, uint64 casterGUID, uint32 spellID)
|
||||
if(GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)this)->SetClientControl(this, !apply);
|
||||
}
|
||||
*/
|
||||
|
||||
bool Unit::IsSitState() const
|
||||
{
|
||||
@@ -12657,4 +12652,217 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
|
||||
bg->HandleKillUnit((Creature*)pVictim, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::SetControlled(bool apply, UnitState state)
|
||||
{
|
||||
if(apply)
|
||||
{
|
||||
if(hasUnitState(state))
|
||||
return;
|
||||
|
||||
addUnitState(state);
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case UNIT_STAT_STUNNED:
|
||||
SetStunned(true);
|
||||
break;
|
||||
case UNIT_STAT_ROOT:
|
||||
if(!hasUnitState(UNIT_STAT_STUNNED))
|
||||
SetRooted(true);
|
||||
break;
|
||||
case UNIT_STAT_CONFUSED:
|
||||
if(!hasUnitState(UNIT_STAT_STUNNED))
|
||||
SetConfused(true);
|
||||
break;
|
||||
case UNIT_STAT_FLEEING:
|
||||
if(!hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_CONFUSED))
|
||||
SetFeared(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case UNIT_STAT_STUNNED: if(HasAuraType(SPELL_AURA_MOD_STUN)) return;
|
||||
else SetStunned(false); break;
|
||||
case UNIT_STAT_ROOT: if(HasAuraType(SPELL_AURA_MOD_ROOT)) return;
|
||||
else SetRooted(false); break;
|
||||
case UNIT_STAT_CONFUSED:if(HasAuraType(SPELL_AURA_MOD_CONFUSE)) return;
|
||||
else SetConfused(false); break;
|
||||
case UNIT_STAT_FLEEING: if(HasAuraType(SPELL_AURA_MOD_FEAR)) return;
|
||||
else SetFeared(false); break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
clearUnitState(state);
|
||||
|
||||
if(hasUnitState(UNIT_STAT_STUNNED))
|
||||
SetStunned(true);
|
||||
else
|
||||
{
|
||||
if(hasUnitState(UNIT_STAT_ROOT))
|
||||
SetRooted(true);
|
||||
|
||||
if(hasUnitState(UNIT_STAT_CONFUSED))
|
||||
SetConfused(true);
|
||||
else if(hasUnitState(UNIT_STAT_FLEEING))
|
||||
SetFeared(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::SetStunned(bool apply)
|
||||
{
|
||||
if(apply)
|
||||
{
|
||||
SetUInt64Value(UNIT_FIELD_TARGET, 0);
|
||||
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
|
||||
CastStop();
|
||||
|
||||
// Creature specific
|
||||
if(GetTypeId() != TYPEID_PLAYER)
|
||||
((Creature*)this)->StopMoving();
|
||||
else
|
||||
SetUnitMovementFlags(0); //Clear movement flags
|
||||
|
||||
WorldPacket data(SMSG_FORCE_MOVE_ROOT, 8);
|
||||
data.append(GetPackGUID());
|
||||
data << uint32(0);
|
||||
SendMessageToSet(&data,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isAlive() && getVictim())
|
||||
SetUInt64Value(UNIT_FIELD_TARGET, getVictim()->GetGUID());
|
||||
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
|
||||
|
||||
if(!hasUnitState(UNIT_STAT_ROOT)) // prevent allow move if have also root effect
|
||||
{
|
||||
WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 8+4);
|
||||
data.append(GetPackGUID());
|
||||
data << uint32(0);
|
||||
SendMessageToSet(&data,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::SetRooted(bool apply)
|
||||
{
|
||||
uint32 apply_stat = UNIT_STAT_ROOT;
|
||||
if(apply)
|
||||
{
|
||||
SetFlag(UNIT_FIELD_FLAGS,(apply_stat<<16)); // probably wrong
|
||||
|
||||
if(GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
SetUnitMovementFlags(0);
|
||||
|
||||
WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10);
|
||||
data.append(GetPackGUID());
|
||||
data << (uint32)2;
|
||||
SendMessageToSet(&data,true);
|
||||
}
|
||||
else
|
||||
((Creature *)this)->StopMoving();
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveFlag(UNIT_FIELD_FLAGS,(apply_stat<<16)); // probably wrong
|
||||
|
||||
if(!hasUnitState(UNIT_STAT_STUNNED)) // prevent allow move if have also stun effect
|
||||
{
|
||||
if(GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 10);
|
||||
data.append(GetPackGUID());
|
||||
data << (uint32)2;
|
||||
SendMessageToSet(&data,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::SetFeared(bool apply)
|
||||
{
|
||||
if(apply)
|
||||
{
|
||||
if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING))
|
||||
return;
|
||||
|
||||
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
|
||||
CastStop();
|
||||
//GetMotionMaster()->MovementExpired(false);
|
||||
Unit *caster = NULL;
|
||||
Unit::AuraList const& fearAuras = GetAurasByType(SPELL_AURA_MOD_FEAR);
|
||||
if(!fearAuras.empty())
|
||||
caster = ObjectAccessor::GetUnit(*this, fearAuras.front()->GetCasterGUID());
|
||||
GetMotionMaster()->MoveFleeing(caster); // caster==NULL processed in MoveFleeing
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
|
||||
GetMotionMaster()->MovementExpired(false);
|
||||
if( GetTypeId() != TYPEID_PLAYER && isAlive() )
|
||||
{
|
||||
// restore appropriate movement generator
|
||||
if(getVictim())
|
||||
GetMotionMaster()->MoveChase(getVictim());
|
||||
else
|
||||
GetMotionMaster()->Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
if (GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)this)->SetClientControl(this, !apply);
|
||||
}
|
||||
|
||||
void Unit::SetConfused(bool apply)
|
||||
{
|
||||
if(apply)
|
||||
{
|
||||
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
|
||||
CastStop();
|
||||
GetMotionMaster()->MoveConfused();
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
|
||||
GetMotionMaster()->MovementExpired(false);
|
||||
if( GetTypeId() != TYPEID_PLAYER && isAlive() )
|
||||
{
|
||||
// restore appropriate movement generator
|
||||
if(getVictim())
|
||||
GetMotionMaster()->MoveChase(getVictim());
|
||||
else
|
||||
GetMotionMaster()->Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
if(GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)this)->SetClientControl(this, !apply);
|
||||
}
|
||||
|
||||
bool Unit::IsInPartyWith(Unit const *unit) const
|
||||
{
|
||||
const Player *p1 = GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
const Player *p2 = unit->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
if(p1 && p2)
|
||||
return p1->IsInSameGroupWith(p2);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Unit::IsInRaidWith(Unit const *unit) const
|
||||
{
|
||||
const Player *p1 = GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
const Player *p2 = unit->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
if(p1 && p2)
|
||||
return p1->IsInSameRaidWith(p2);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
+10
-3
@@ -37,6 +37,8 @@
|
||||
#include "Database/DBCStructure.h"
|
||||
#include <list>
|
||||
|
||||
#define WORLD_TRIGGER 12999
|
||||
|
||||
enum SpellInterruptFlags
|
||||
{
|
||||
SPELL_INTERRUPT_FLAG_MOVEMENT = 0x01, // why need this for instant?
|
||||
@@ -871,6 +873,8 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
bool IsHostileToPlayers() const;
|
||||
bool IsFriendlyTo(Unit const* unit) const;
|
||||
bool IsNeutralToAll() const;
|
||||
bool IsInPartyWith(Unit const* unit) const;
|
||||
bool IsInRaidWith(Unit const* unit) const;
|
||||
bool IsContestedGuard() const
|
||||
{
|
||||
if(FactionTemplateEntry const* entry = getFactionTemplateEntry())
|
||||
@@ -1055,7 +1059,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
|
||||
return this;
|
||||
}
|
||||
Player* GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
Player* GetCharmerOrOwnerPlayerOrPlayerItself() const;
|
||||
|
||||
void SetPet(Pet* pet);
|
||||
void SetCharm(Unit* pet);
|
||||
@@ -1348,8 +1352,11 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
uint32 GetUnitMovementFlags() const { return m_unit_movement_flags; }
|
||||
void SetUnitMovementFlags(uint32 f) { m_unit_movement_flags = f; }
|
||||
|
||||
void SetFeared(bool apply, uint64 casterGUID = 0, uint32 spellID = 0);
|
||||
void SetConfused(bool apply, uint64 casterGUID = 0, uint32 spellID = 0);
|
||||
void SetControlled(bool apply, UnitState state);
|
||||
void SetFeared(bool apply/*, uint64 casterGUID = 0, uint32 spellID = 0*/);
|
||||
void SetConfused(bool apply/*, uint64 casterGUID = 0, uint32 spellID = 0*/);
|
||||
void SetStunned(bool apply);
|
||||
void SetRooted(bool apply);
|
||||
|
||||
void AddComboPointHolder(uint32 lowguid) { m_ComboPointHolders.insert(lowguid); }
|
||||
void RemoveComboPointHolder(uint32 lowguid) { m_ComboPointHolders.erase(lowguid); }
|
||||
|
||||
+108
-298
@@ -10,333 +10,143 @@
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "GridDefines.h"
|
||||
#include "Policies/SingletonImp.h"
|
||||
#include "WaypointManager.h"
|
||||
#include "ProgressBar.h"
|
||||
#include "MapManager.h"
|
||||
#include "ObjectMgr.h"
|
||||
|
||||
INSTANTIATE_SINGLETON_1(WaypointManager);
|
||||
UNORDERED_MAP<uint32, WaypointPath*> waypoint_map;
|
||||
WaypointStore WaypointMgr;
|
||||
|
||||
bool WaypointBehavior::isEmpty()
|
||||
void WaypointStore::Free()
|
||||
{
|
||||
if (emote || spell || model1 || model2)
|
||||
return false;
|
||||
|
||||
for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
|
||||
if(textid[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
waypoint_map.clear();
|
||||
}
|
||||
|
||||
WaypointBehavior::WaypointBehavior(const WaypointBehavior &b)
|
||||
void WaypointStore::Load()
|
||||
{
|
||||
emote = b.emote;
|
||||
spell = b.spell;
|
||||
model1 = b.model1;
|
||||
model2 = b.model2;
|
||||
for(int i=0; i < MAX_WAYPOINT_TEXT; ++i)
|
||||
textid[i] = b.textid[i];
|
||||
}
|
||||
|
||||
void WaypointManager::Load()
|
||||
{
|
||||
Cleanup();
|
||||
|
||||
uint32 total_paths = 0;
|
||||
uint32 total_nodes = 0;
|
||||
uint32 total_behaviors = 0;
|
||||
|
||||
QueryResult *result = WorldDatabase.Query("SELECT id, COUNT(point) FROM creature_movement GROUP BY id");
|
||||
if(result)
|
||||
QueryResult *result = WorldDatabase.PQuery("SELECT MAX(`id`) FROM `waypoint_data");
|
||||
if(!result)
|
||||
{
|
||||
total_paths = result->GetRowCount();
|
||||
barGoLink bar( total_paths );
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
uint32 id = fields[0].GetUInt32();
|
||||
uint32 count = fields[1].GetUInt32();
|
||||
m_pathMap[id].resize(count);
|
||||
|
||||
total_nodes += count;
|
||||
bar.step();
|
||||
} while( result->NextRow() );
|
||||
delete result;
|
||||
sLog.outError(" an error occured while loading the table `waypoint_data` ( maybe it doesn't exist ?)\n");
|
||||
exit(1); // Stop server at loading non exited table or not accessable table
|
||||
}
|
||||
|
||||
result = WorldDatabase.Query("SELECT position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, id, point FROM creature_movement");
|
||||
if(result)
|
||||
records = (*result)[0].GetUInt32();
|
||||
delete result;
|
||||
|
||||
|
||||
result = WorldDatabase.PQuery("SELECT `id`,`point`,`position_x`,`position_y`,`position_z`,`move_flag`,`delay`,`action`,`action_chance` FROM `waypoint_data` ORDER BY `id`, `point`");
|
||||
if(!result)
|
||||
{
|
||||
barGoLink bar( result->GetRowCount() );
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
uint32 point = fields[15].GetUInt32();
|
||||
uint32 id = fields[14].GetUInt32();
|
||||
|
||||
WaypointPath &path = m_pathMap[id];
|
||||
// the cleanup queries make sure the following is true
|
||||
assert(point >= 1 && point <= path.size());
|
||||
WaypointNode &node = path[point-1];
|
||||
|
||||
node.x = fields[0].GetFloat();
|
||||
node.y = fields[1].GetFloat();
|
||||
node.z = fields[2].GetFloat();
|
||||
node.orientation = fields[3].GetFloat();
|
||||
node.delay = fields[6].GetUInt16();
|
||||
|
||||
// prevent using invalid coordinates
|
||||
if(!Trinity::IsValidMapCoord(node.x, node.y, node.z, node.orientation))
|
||||
{
|
||||
QueryResult *result1 = WorldDatabase.PQuery("SELECT id, map FROM creature WHERE guid = '%u'", id);
|
||||
if(result1)
|
||||
sLog.outErrorDb("ERROR: Creature (guidlow %d, entry %d) have invalid coordinates in his waypoint %d (X: %f, Y: %f).",
|
||||
id, result1->Fetch()[0].GetUInt32(), point, node.x, node.y);
|
||||
else
|
||||
sLog.outErrorDb("ERROR: Waypoint path %d, have invalid coordinates in his waypoint %d (X: %f, Y: %f).",
|
||||
id, point, node.x, node.y);
|
||||
|
||||
Trinity::NormalizeMapCoord(node.x);
|
||||
Trinity::NormalizeMapCoord(node.y);
|
||||
if(result1)
|
||||
{
|
||||
node.z = MapManager::Instance ().GetBaseMap(result1->Fetch()[1].GetUInt32())->GetHeight(node.x, node.y, node.z);
|
||||
delete result1;
|
||||
}
|
||||
WorldDatabase.PExecute("UPDATE creature_movement SET position_x = '%f', position_y = '%f', position_z = '%f' WHERE id = '%u' AND point = '%u'", node.x, node.y, node.z, id, point);
|
||||
}
|
||||
|
||||
WaypointBehavior be;
|
||||
be.model1 = fields[4].GetUInt32();
|
||||
be.model2 = fields[5].GetUInt32();
|
||||
be.emote = fields[7].GetUInt32();
|
||||
be.spell = fields[8].GetUInt32();
|
||||
|
||||
for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
|
||||
{
|
||||
be.textid[i] = fields[9+i].GetUInt32();
|
||||
if(be.textid[i])
|
||||
{
|
||||
if (be.textid[i] < MIN_DB_SCRIPT_STRING_ID || be.textid[i] >= MAX_DB_SCRIPT_STRING_ID)
|
||||
{
|
||||
sLog.outErrorDb( "Table `db_script_string` not have string id %u", be.textid[i]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save memory by not storing empty behaviors
|
||||
if(!be.isEmpty())
|
||||
{
|
||||
node.behavior = new WaypointBehavior(be);
|
||||
++total_behaviors;
|
||||
}
|
||||
else
|
||||
node.behavior = NULL;
|
||||
bar.step();
|
||||
} while( result->NextRow() );
|
||||
delete result;
|
||||
}
|
||||
sLog.outString( ">> Loaded %u paths, %u nodes and %u behaviors", total_paths, total_nodes, total_behaviors);
|
||||
}
|
||||
|
||||
void WaypointManager::Cleanup()
|
||||
{
|
||||
// check if points need to be renumbered and do it
|
||||
if(QueryResult *result = WorldDatabase.Query("SELECT 1 from creature_movement As T WHERE point <> (SELECT COUNT(*) FROM creature_movement WHERE id = T.id AND point <= T.point) LIMIT 1"))
|
||||
{
|
||||
delete result;
|
||||
WorldDatabase.DirectExecute("CREATE TEMPORARY TABLE temp LIKE creature_movement");
|
||||
WorldDatabase.DirectExecute("INSERT INTO temp SELECT * FROM creature_movement");
|
||||
WorldDatabase.DirectExecute("ALTER TABLE creature_movement DROP PRIMARY KEY");
|
||||
WorldDatabase.DirectExecute("UPDATE creature_movement AS T SET point = (SELECT COUNT(*) FROM temp WHERE id = T.id AND point <= T.point)");
|
||||
WorldDatabase.DirectExecute("ALTER TABLE creature_movement ADD PRIMARY KEY (id, point)");
|
||||
WorldDatabase.DirectExecute("DROP TABLE temp");
|
||||
assert(!(result = WorldDatabase.Query("SELECT 1 from creature_movement As T WHERE point <> (SELECT COUNT(*) FROM creature_movement WHERE id = T.id AND point <= T.point) LIMIT 1")));
|
||||
}
|
||||
}
|
||||
|
||||
void WaypointManager::Unload()
|
||||
{
|
||||
for(WaypointPathMap::iterator itr = m_pathMap.begin(); itr != m_pathMap.end(); ++itr)
|
||||
_clearPath(itr->second);
|
||||
m_pathMap.clear();
|
||||
}
|
||||
|
||||
void WaypointManager::_clearPath(WaypointPath &path)
|
||||
{
|
||||
for(WaypointPath::iterator itr = path.begin(); itr != path.end(); ++itr)
|
||||
if(itr->behavior)
|
||||
delete itr->behavior;
|
||||
path.clear();
|
||||
}
|
||||
|
||||
/// - Insert after the last point
|
||||
void WaypointManager::AddLastNode(uint32 id, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
|
||||
{
|
||||
_addNode(id, GetLastPoint(id, 0) + 1, x, y, z, o, delay, wpGuid);
|
||||
}
|
||||
|
||||
/// - Insert after a certain point
|
||||
void WaypointManager::AddAfterNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
|
||||
{
|
||||
for(uint32 i = GetLastPoint(id, 0); i > point; i--)
|
||||
WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point+1 WHERE id='%u' AND point='%u'", id, i);
|
||||
|
||||
_addNode(id, point + 1, x, y, z, o, delay, wpGuid);
|
||||
}
|
||||
|
||||
/// - Insert without checking for collision
|
||||
void WaypointManager::_addNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
|
||||
{
|
||||
if(point == 0) return; // counted from 1 in the DB
|
||||
WorldDatabase.PExecuteLog("INSERT INTO creature_movement (id,point,position_x,position_y,position_z,orientation,wpguid,waittime) VALUES ('%u','%u','%f', '%f', '%f', '%f', '%d', '%d')", id, point, x, y, z, o, wpGuid, delay);
|
||||
WaypointPathMap::iterator itr = m_pathMap.find(id);
|
||||
if(itr == m_pathMap.end())
|
||||
itr = m_pathMap.insert(WaypointPathMap::value_type(id, WaypointPath())).first;
|
||||
itr->second.insert(itr->second.begin() + (point - 1), WaypointNode(x, y, z, o, delay, NULL));
|
||||
}
|
||||
|
||||
uint32 WaypointManager::GetLastPoint(uint32 id, uint32 default_notfound)
|
||||
{
|
||||
uint32 point = default_notfound;
|
||||
/*QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'", id);
|
||||
if( result )
|
||||
{
|
||||
point = (*result)[0].GetUInt32()+1;
|
||||
delete result;
|
||||
}*/
|
||||
WaypointPathMap::iterator itr = m_pathMap.find(id);
|
||||
if(itr != m_pathMap.end() && itr->second.size() != 0)
|
||||
point = itr->second.size();
|
||||
return point;
|
||||
}
|
||||
|
||||
void WaypointManager::DeleteNode(uint32 id, uint32 point)
|
||||
{
|
||||
if(point == 0) return; // counted from 1 in the DB
|
||||
WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id='%u' AND point='%u'", id, point);
|
||||
WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point-1 WHERE id='%u' AND point>'%u'", id, point);
|
||||
WaypointPathMap::iterator itr = m_pathMap.find(id);
|
||||
if(itr != m_pathMap.end() && point <= itr->second.size())
|
||||
itr->second.erase(itr->second.begin() + (point-1));
|
||||
}
|
||||
|
||||
void WaypointManager::DeletePath(uint32 id)
|
||||
{
|
||||
WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id='%u'", id);
|
||||
WaypointPathMap::iterator itr = m_pathMap.find(id);
|
||||
if(itr != m_pathMap.end())
|
||||
_clearPath(itr->second);
|
||||
// the path is not removed from the map, just cleared
|
||||
// WMGs have pointers to the path, so deleting them would crash
|
||||
// this wastes some memory, but these functions are
|
||||
// only meant to be called by GM commands
|
||||
}
|
||||
|
||||
void WaypointManager::SetNodePosition(uint32 id, uint32 point, float x, float y, float z)
|
||||
{
|
||||
if(point == 0) return; // counted from 1 in the DB
|
||||
WorldDatabase.PExecuteLog("UPDATE creature_movement SET position_x = '%f',position_y = '%f',position_z = '%f' where id = '%u' AND point='%u'", x, y, z, id, point);
|
||||
WaypointPathMap::iterator itr = m_pathMap.find(id);
|
||||
if(itr != m_pathMap.end() && point <= itr->second.size())
|
||||
{
|
||||
itr->second[point-1].x = x;
|
||||
itr->second[point-1].y = y;
|
||||
itr->second[point-1].z = z;
|
||||
}
|
||||
}
|
||||
|
||||
void WaypointManager::SetNodeText(uint32 id, uint32 point, const char *text_field, const char *text)
|
||||
{
|
||||
if(point == 0) return; // counted from 1 in the DB
|
||||
if(!text_field) return;
|
||||
std::string field = text_field;
|
||||
WorldDatabase.escape_string(field);
|
||||
|
||||
if(!text)
|
||||
{
|
||||
WorldDatabase.PExecuteLog("UPDATE creature_movement SET %s=NULL WHERE id='%u' AND point='%u'", field.c_str(), id, point);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string text2 = text;
|
||||
WorldDatabase.escape_string(text2);
|
||||
WorldDatabase.PExecuteLog("UPDATE creature_movement SET %s='%s' WHERE id='%u' AND point='%u'", field.c_str(), text2.c_str(), id, point);
|
||||
sLog.outErrorDb("The table `creature_addon` is empty or corrupted");
|
||||
return;
|
||||
}
|
||||
|
||||
WaypointPathMap::iterator itr = m_pathMap.find(id);
|
||||
if(itr != m_pathMap.end() && point <= itr->second.size())
|
||||
{
|
||||
WaypointNode &node = itr->second[point-1];
|
||||
if(!node.behavior) node.behavior = new WaypointBehavior();
|
||||
WaypointPath* path_data;
|
||||
uint32 total_records = result->GetRowCount();
|
||||
|
||||
// if(field == "text1") node.behavior->text[0] = text ? text : "";
|
||||
// if(field == "text2") node.behavior->text[1] = text ? text : "";
|
||||
// if(field == "text3") node.behavior->text[2] = text ? text : "";
|
||||
// if(field == "text4") node.behavior->text[3] = text ? text : "";
|
||||
// if(field == "text5") node.behavior->text[4] = text ? text : "";
|
||||
if(field == "emote") node.behavior->emote = text ? atoi(text) : 0;
|
||||
if(field == "spell") node.behavior->spell = text ? atoi(text) : 0;
|
||||
if(field == "model1") node.behavior->model1 = text ? atoi(text) : 0;
|
||||
if(field == "model2") node.behavior->model2 = text ? atoi(text) : 0;
|
||||
}
|
||||
barGoLink bar( total_records);
|
||||
Field *fields;
|
||||
uint32 last_id = 0;
|
||||
|
||||
do
|
||||
{
|
||||
fields = result->Fetch();
|
||||
uint32 id = fields[0].GetUInt32();
|
||||
bar.step();
|
||||
WaypointData *wp = new WaypointData;
|
||||
|
||||
if(last_id != id)
|
||||
path_data = new WaypointPath;
|
||||
|
||||
float x,y,z;
|
||||
x = fields[2].GetFloat();
|
||||
y = fields[3].GetFloat();
|
||||
z = fields[4].GetFloat();
|
||||
|
||||
Trinity::NormalizeMapCoord(x);
|
||||
Trinity::NormalizeMapCoord(y);
|
||||
|
||||
wp->id = fields[1].GetUInt32();
|
||||
wp->x = x;
|
||||
wp->y = y;
|
||||
wp->z = z;
|
||||
wp->run = fields[5].GetBool();
|
||||
wp->delay = fields[6].GetUInt32();
|
||||
wp->event_id = fields[7].GetUInt32();
|
||||
wp->event_chance = fields[8].GetUInt8();
|
||||
|
||||
path_data->push_back(wp);
|
||||
|
||||
if(id != last_id)
|
||||
waypoint_map[id] = path_data;
|
||||
|
||||
last_id = id;
|
||||
|
||||
} while(result->NextRow()) ;
|
||||
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
void WaypointManager::CheckTextsExistance(std::set<int32>& ids)
|
||||
void WaypointStore::UpdatePath(uint32 id)
|
||||
{
|
||||
WaypointPathMap::iterator pmItr = m_pathMap.begin();
|
||||
for ( ; pmItr != m_pathMap.end(); ++pmItr)
|
||||
|
||||
if(waypoint_map.find(id)!= waypoint_map.end())
|
||||
waypoint_map[id]->clear();
|
||||
|
||||
QueryResult *result;
|
||||
|
||||
result = WorldDatabase.PQuery("SELECT `id`,`point`,`position_x`,`position_y`,`position_z`,`move_flag`,`delay`,`action`,`action_chance` FROM `waypoint_data` WHERE id = %u ORDER BY `point`", id);
|
||||
|
||||
if(!result)
|
||||
return;
|
||||
|
||||
WaypointPath* path_data;
|
||||
|
||||
path_data = new WaypointPath;
|
||||
|
||||
Field *fields;
|
||||
|
||||
do
|
||||
{
|
||||
for (int i = 0; i < pmItr->second.size(); ++i)
|
||||
{
|
||||
if (!pmItr->second[i].behavior)
|
||||
continue;
|
||||
fields = result->Fetch();
|
||||
uint32 id = fields[0].GetUInt32();
|
||||
|
||||
WaypointData *wp = new WaypointData;
|
||||
|
||||
// Now we check text existence and put all zero texts ids to the end of array
|
||||
float x,y,z;
|
||||
x = fields[2].GetFloat();
|
||||
y = fields[3].GetFloat();
|
||||
z = fields[4].GetFloat();
|
||||
|
||||
// Counting leading zeros for futher textid shift
|
||||
int zeroCount = 0;
|
||||
for (int j = 0; j < MAX_WAYPOINT_TEXT; ++j)
|
||||
{
|
||||
if (!pmItr->second[i].behavior->textid[j])
|
||||
{
|
||||
++zeroCount;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!objmgr.GetTrinityStringLocale(pmItr->second[i].behavior->textid[j]))
|
||||
{
|
||||
sLog.outErrorDb("ERROR: Some waypoint has textid%u with not existing %u text.", j, pmItr->second[i].behavior->textid[j]);
|
||||
pmItr->second[i].behavior->textid[j] = 0;
|
||||
++zeroCount;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
ids.erase(pmItr->second[i].behavior->textid[j]);
|
||||
Trinity::NormalizeMapCoord(x);
|
||||
Trinity::NormalizeMapCoord(y);
|
||||
|
||||
// Shifting check
|
||||
if (zeroCount)
|
||||
{
|
||||
// Correct textid but some zeros leading, so move it forward.
|
||||
pmItr->second[i].behavior->textid[j-zeroCount] = pmItr->second[i].behavior->textid[j];
|
||||
pmItr->second[i].behavior->textid[j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
wp->id = fields[1].GetUInt32();
|
||||
wp->x = x;
|
||||
wp->y = y;
|
||||
wp->z = z;
|
||||
wp->run = fields[5].GetBool();
|
||||
wp->delay = fields[6].GetUInt32();
|
||||
wp->event_id = fields[7].GetUInt32();
|
||||
wp->event_chance = fields[8].GetUInt8();
|
||||
|
||||
path_data->push_back(wp);
|
||||
|
||||
}while (result->NextRow());
|
||||
|
||||
waypoint_map[id] = path_data;
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
+25
-57
@@ -22,72 +22,40 @@
|
||||
#define TRINITY_WAYPOINTMANAGER_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "Utilities/UnorderedMap.h"
|
||||
|
||||
#define MAX_WAYPOINT_TEXT 5
|
||||
struct WaypointBehavior
|
||||
struct WaypointData
|
||||
{
|
||||
uint32 emote;
|
||||
uint32 spell;
|
||||
int32 textid[MAX_WAYPOINT_TEXT];
|
||||
uint32 model1;
|
||||
uint32 model2;
|
||||
|
||||
bool isEmpty();
|
||||
WaypointBehavior() {}
|
||||
WaypointBehavior(const WaypointBehavior &b);
|
||||
};
|
||||
|
||||
struct WaypointNode
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float orientation;
|
||||
uint32 id;
|
||||
float x,y,z;
|
||||
bool run;
|
||||
uint32 delay;
|
||||
WaypointBehavior * behavior;
|
||||
WaypointNode() {}
|
||||
WaypointNode(float _x, float _y, float _z, float _o, uint32 _delay, WaypointBehavior * _behavior)
|
||||
: x(_x), y(_y), z(_z), orientation(_o), delay(_delay), behavior(_behavior) {}
|
||||
uint32 event_id;
|
||||
uint8 event_chance;
|
||||
};
|
||||
|
||||
typedef std::vector<WaypointNode> WaypointPath;
|
||||
typedef std::vector<WaypointData*> WaypointPath;
|
||||
extern UNORDERED_MAP<uint32, WaypointPath*> waypoint_map;
|
||||
|
||||
class WaypointManager
|
||||
class WaypointStore
|
||||
{
|
||||
public:
|
||||
WaypointManager() {}
|
||||
~WaypointManager() { Unload(); }
|
||||
|
||||
void Load();
|
||||
void Unload();
|
||||
|
||||
void Cleanup();
|
||||
|
||||
WaypointPath *GetPath(uint32 id)
|
||||
private :
|
||||
uint32 records;
|
||||
|
||||
public:
|
||||
void UpdatePath(uint32 id);
|
||||
void Load();
|
||||
void Free();
|
||||
|
||||
WaypointPath* GetPath(uint32 id)
|
||||
{
|
||||
WaypointPathMap::iterator itr = m_pathMap.find(id);
|
||||
return itr != m_pathMap.end() ? &itr->second : NULL;
|
||||
}
|
||||
|
||||
void AddLastNode(uint32 id, float x, float y, float z, float o, uint32 delay, uint32 wpGuid);
|
||||
void AddAfterNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid);
|
||||
uint32 GetLastPoint(uint32 id, uint32 default_notfound);
|
||||
void DeleteNode(uint32 id, uint32 point);
|
||||
void DeletePath(uint32 id);
|
||||
void SetNodePosition(uint32 id, uint32 point, float x, float y, float z);
|
||||
void SetNodeText(uint32 id, uint32 point, const char *text_field, const char *text);
|
||||
void CheckTextsExistance(std::set<int32>& ids);
|
||||
|
||||
private:
|
||||
void _addNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid);
|
||||
void _clearPath(WaypointPath &path);
|
||||
|
||||
typedef UNORDERED_MAP<uint32, WaypointPath> WaypointPathMap;
|
||||
WaypointPathMap m_pathMap;
|
||||
if(waypoint_map.find(id) != waypoint_map.end())
|
||||
return waypoint_map[id];
|
||||
else return 0;
|
||||
}
|
||||
|
||||
inline uint32 GetRecordsCount() { return records; }
|
||||
};
|
||||
|
||||
#define WaypointMgr Trinity::Singleton<WaypointManager>::Instance()
|
||||
extern WaypointStore WaypointMgr;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
|
||||
*
|
||||
* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* 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
|
||||
@@ -10,210 +8,205 @@
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
creature_movement Table
|
||||
|
||||
alter table creature_movement add `textid1` int(11) NOT NULL default '0';
|
||||
alter table creature_movement add `textid2` int(11) NOT NULL default '0';
|
||||
alter table creature_movement add `textid3` int(11) NOT NULL default '0';
|
||||
alter table creature_movement add `textid4` int(11) NOT NULL default '0';
|
||||
alter table creature_movement add `textid5` int(11) NOT NULL default '0';
|
||||
alter table creature_movement add `emote` int(10) unsigned default '0';
|
||||
alter table creature_movement add `spell` int(5) unsigned default '0';
|
||||
alter table creature_movement add `wpguid` int(11) default '0';
|
||||
|
||||
*/
|
||||
|
||||
//Basic header
|
||||
#include <ctime>
|
||||
|
||||
#include "WaypointMovementGenerator.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Creature.h"
|
||||
#include "DestinationHolderImp.h"
|
||||
//Accessors
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "World.h"
|
||||
//Creature-specific headers
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "WaypointManager.h"
|
||||
//Player-Specific
|
||||
#include "Player.h"
|
||||
//Visual
|
||||
#include "ProgressBar.h"
|
||||
#include "MapManager.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
//-----------------------------------------------//
|
||||
template<class T>
|
||||
void
|
||||
WaypointMovementGenerator<Creature>::LoadPath(Creature &c)
|
||||
WaypointMovementGenerator<T>::Initialize(T &u){}
|
||||
|
||||
template<>
|
||||
void
|
||||
WaypointMovementGenerator<Creature>::Initialize(Creature &u)
|
||||
{
|
||||
sLog.outDetail("LoadPath: loading waypoint path for creature %d,%d", c.GetGUIDLow(), c.GetDBTableGUIDLow());
|
||||
|
||||
i_path = WaypointMgr.GetPath(c.GetDBTableGUIDLow());
|
||||
if(!i_path)
|
||||
{
|
||||
sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %d) doesn't have waypoint path",
|
||||
c.GetName(), c.GetEntry(), c.GetDBTableGUIDLow());
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 node_count = i_path->size();
|
||||
i_hasDone.resize(node_count);
|
||||
for(uint32 i = 0; i < node_count-1; i++)
|
||||
i_hasDone[i] = false;
|
||||
|
||||
// to prevent a misbehaviour inside "update"
|
||||
// update is always called with the next wp - but the wpSys needs the current
|
||||
// so when the routine is called the first time, wpSys gets the last waypoint
|
||||
// and this prevents the system from performing text/emote, etc
|
||||
i_hasDone[node_count - 1] = true;
|
||||
i_currentNode = -1;
|
||||
u.StopMoving();
|
||||
if(!path_id)
|
||||
path_id = u.GetWaypointPath();
|
||||
waypoints = WaypointMgr.GetPath(path_id);
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
WaypointMovementGenerator<Creature>::ClearWaypoints()
|
||||
WaypointMovementGenerator<Creature>::Finalize(Creature &u){}
|
||||
|
||||
template<>
|
||||
void
|
||||
WaypointMovementGenerator<Player>::Finalize(Player &u){}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
WaypointMovementGenerator<T>::MovementInform(T &unit){}
|
||||
|
||||
template<>
|
||||
void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit)
|
||||
{
|
||||
i_path = NULL;
|
||||
unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
|
||||
}
|
||||
|
||||
void
|
||||
WaypointMovementGenerator<Creature>::Initialize()
|
||||
template<>
|
||||
bool WaypointMovementGenerator<Creature>::GetDestination(float &x, float &y, float &z) const
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
|
||||
{
|
||||
if(!&creature)
|
||||
return true;
|
||||
|
||||
// Waypoint movement can be switched on/off
|
||||
// This is quite handy for escort quests and other stuff
|
||||
if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
|
||||
return true;
|
||||
|
||||
// prevent a crash at empty waypoint path.
|
||||
if(!i_path || i_path->empty())
|
||||
return true;
|
||||
|
||||
// i_path was modified by chat commands for example
|
||||
if(i_path->size() != i_hasDone.size())
|
||||
i_hasDone.resize(i_path->size());
|
||||
if(i_currentNode >= i_path->size())
|
||||
i_currentNode = 0;
|
||||
|
||||
CreatureTraveller traveller(creature);
|
||||
|
||||
i_nextMoveTime.Update(diff);
|
||||
i_destinationHolder.UpdateTraveller(traveller, diff, false, true);
|
||||
|
||||
// creature has been stoped in middle of the waypoint segment
|
||||
if (!i_destinationHolder.HasArrived() && creature.IsStopped())
|
||||
{
|
||||
if( i_nextMoveTime.Passed()) // Timer has elapsed, meaning this part controlled it
|
||||
{
|
||||
SetStopedByPlayer(false);
|
||||
// Now we re-set destination to same node and start travel
|
||||
creature.addUnitState(UNIT_STAT_ROAMING);
|
||||
if (creature.canFly())
|
||||
creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
|
||||
const WaypointNode &node = i_path->at(i_currentNode);
|
||||
i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
|
||||
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
|
||||
}
|
||||
else // if( !i_nextMoveTime.Passed())
|
||||
{ // unexpected end of timer && creature stopped && not at end of segment
|
||||
if (!IsStopedByPlayer())
|
||||
{ // Put 30 seconds delay
|
||||
i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER);
|
||||
i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER);
|
||||
SetStopedByPlayer(true); // Mark we did it
|
||||
}
|
||||
}
|
||||
return true; // Abort here this update
|
||||
}
|
||||
|
||||
if( creature.IsStopped())
|
||||
{
|
||||
uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1;
|
||||
|
||||
if (!i_hasDone[idx])
|
||||
{
|
||||
if (i_path->at(idx).orientation !=100)
|
||||
creature.SetOrientation(i_path->at(idx).orientation);
|
||||
|
||||
if(WaypointBehavior *behavior = i_path->at(idx).behavior)
|
||||
{
|
||||
if(behavior->emote != 0)
|
||||
creature.SetUInt32Value(UNIT_NPC_EMOTESTATE,behavior->emote);
|
||||
if(behavior->spell != 0)
|
||||
creature.CastSpell(&creature,behavior->spell, false);
|
||||
if(behavior->model1 != 0)
|
||||
creature.SetDisplayId(behavior->model1);
|
||||
if(behavior->textid[0])
|
||||
{
|
||||
// Not only one text is set
|
||||
if( behavior->textid[1] )
|
||||
{
|
||||
// Select one from max 5 texts (0 and 1 already checked)
|
||||
int i = 2;
|
||||
for( ; i < MAX_WAYPOINT_TEXT; ++i )
|
||||
if( !behavior->textid[i] )
|
||||
break;
|
||||
|
||||
creature.Say(behavior->textid[rand() % i], 0, 0);
|
||||
}
|
||||
else
|
||||
creature.Say(behavior->textid[0], 0, 0);
|
||||
}
|
||||
} // wpBehaviour found
|
||||
i_hasDone[idx] = true;
|
||||
MovementInform(creature);
|
||||
} // HasDone == false
|
||||
} // i_creature.IsStopped()
|
||||
|
||||
if( i_nextMoveTime.Passed() ) // This is at the end of waypoint segment or has been stopped by player
|
||||
{
|
||||
if( creature.IsStopped() ) // If stopped then begin a new move segment
|
||||
{
|
||||
creature.addUnitState(UNIT_STAT_ROAMING);
|
||||
if (creature.canFly())
|
||||
creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
|
||||
const WaypointNode &node = i_path->at(i_currentNode);
|
||||
i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
|
||||
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
|
||||
uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1;
|
||||
|
||||
if (i_path->at(idx).orientation !=100)
|
||||
creature.SetOrientation(i_path->at(idx).orientation);
|
||||
|
||||
if(WaypointBehavior *behavior = i_path->at(idx).behavior )
|
||||
{
|
||||
i_hasDone[idx] = false;
|
||||
if(behavior->model2 != 0)
|
||||
creature.SetDisplayId(behavior->model2);
|
||||
|
||||
creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
|
||||
}
|
||||
}
|
||||
else // If not stopped then stop it and set the reset of TimeTracker to waittime
|
||||
{
|
||||
creature.StopMoving();
|
||||
SetStopedByPlayer(false);
|
||||
i_nextMoveTime.Reset(i_path->at(i_currentNode).delay);
|
||||
++i_currentNode;
|
||||
if( i_currentNode >= i_path->size() )
|
||||
i_currentNode = 0;
|
||||
}
|
||||
}
|
||||
if(i_destinationHolder.HasArrived())
|
||||
return false;
|
||||
|
||||
i_destinationHolder.GetDestination(x, y, z);
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit)
|
||||
template<>
|
||||
bool WaypointMovementGenerator<Player>::GetDestination(float &x, float &y, float &z) const
|
||||
{
|
||||
if(unit.AI())
|
||||
unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
void WaypointMovementGenerator<Creature>::Reset(Creature &unit){}
|
||||
|
||||
template<>
|
||||
void WaypointMovementGenerator<Player>::Reset(Player &unit){}
|
||||
|
||||
template<>
|
||||
void WaypointMovementGenerator<Creature>::InitTraveller(Creature &unit, const WaypointData &node)
|
||||
{
|
||||
node.run ? unit.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE): unit.AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
|
||||
|
||||
unit.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
|
||||
unit.SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
|
||||
|
||||
if(unit.canFly())
|
||||
unit.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
|
||||
|
||||
unit.addUnitState(UNIT_STAT_ROAMING);
|
||||
}
|
||||
|
||||
template<>
|
||||
void WaypointMovementGenerator<Player>::InitTraveller(Player &unit, const WaypointData &node){}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
WaypointMovementGenerator<T>::Update(T &unit, const uint32 &diff)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool
|
||||
WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff)
|
||||
{
|
||||
if(!&unit)
|
||||
return true;
|
||||
|
||||
if(!path_id)
|
||||
return false;
|
||||
|
||||
// Waypoint movement can be switched on/off
|
||||
// This is quite handy for escort quests and other stuff
|
||||
if(unit.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
|
||||
return true;
|
||||
|
||||
// Clear the generator if the path doesn't exist
|
||||
if(!waypoints || !waypoints->size())
|
||||
return false;
|
||||
|
||||
Traveller<Creature> traveller(unit);
|
||||
|
||||
i_nextMoveTime.Update(diff);
|
||||
i_destinationHolder.UpdateTraveller(traveller, diff, false, true);
|
||||
|
||||
if(i_nextMoveTime.Passed())
|
||||
{
|
||||
if(unit.IsStopped())
|
||||
{
|
||||
if(StopedByPlayer)
|
||||
{
|
||||
InitTraveller(unit,node);
|
||||
i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
|
||||
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
|
||||
StopedByPlayer = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(i_currentNode == waypoints->size() - 1) //If that's our last waypoint
|
||||
{
|
||||
if(repeating) //If the movement is repeating
|
||||
i_currentNode = 0; //Start moving all over again
|
||||
else
|
||||
{
|
||||
unit.GetMotionMaster()->Initialize();
|
||||
return false; //Clear the waypoint movement
|
||||
}
|
||||
}
|
||||
else
|
||||
i_currentNode++;
|
||||
|
||||
node = *(waypoints->at(i_currentNode));
|
||||
InitTraveller(unit,node);
|
||||
i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
|
||||
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
|
||||
}
|
||||
else
|
||||
{
|
||||
//Determine waittime
|
||||
if(node.delay)
|
||||
i_nextMoveTime.Reset(node.delay);
|
||||
else
|
||||
i_nextMoveTime.Reset(100); //Prevents some lag
|
||||
|
||||
if(node.event_id && rand()%100 < node.event_chance && !ExecuteScript)
|
||||
{
|
||||
sWorld.ScriptsStart(sWaypointScripts, node.event_id, &unit, NULL);
|
||||
ExecuteScript = true;
|
||||
}
|
||||
|
||||
MovementInform(unit);
|
||||
unit.UpdateWaypointID(i_currentNode);
|
||||
traveller.Relocation(node.x, node.y, node.z);
|
||||
unit.clearUnitState(UNIT_STAT_MOVING);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(unit.IsStopped() && !i_destinationHolder.HasArrived())
|
||||
{
|
||||
if(!StopedByPlayer)
|
||||
{
|
||||
i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER);
|
||||
i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER);
|
||||
StopedByPlayer = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template void WaypointMovementGenerator<Player>::Initialize(Player &);
|
||||
template bool WaypointMovementGenerator<Player>::Update(Player &, const uint32 &);
|
||||
template void WaypointMovementGenerator<Player>::MovementInform(Player &);
|
||||
|
||||
//----------------------------------------------------//
|
||||
void
|
||||
FlightPathMovementGenerator::LoadPath(Player &)
|
||||
|
||||
@@ -50,64 +50,41 @@ class TRINITY_DLL_SPEC PathMovementBase
|
||||
|
||||
inline bool MovementInProgress(void) const { return i_currentNode < i_path.Size(); }
|
||||
|
||||
// template pattern, not defined .. override required
|
||||
void LoadPath(T &);
|
||||
void ReloadPath(T &);
|
||||
uint32 GetCurrentNode() const { return i_currentNode; }
|
||||
|
||||
|
||||
protected:
|
||||
uint32 i_currentNode;
|
||||
DestinationHolder< Traveller<T> > i_destinationHolder;
|
||||
P i_path;
|
||||
};
|
||||
|
||||
/** WaypointMovementGenerator loads a series of way points
|
||||
* from the DB and apply it to the creature's movement generator.
|
||||
* Hence, the creature will move according to its predefined way points.
|
||||
*/
|
||||
|
||||
template<class T>
|
||||
class TRINITY_DLL_SPEC WaypointMovementGenerator;
|
||||
|
||||
template<>
|
||||
class TRINITY_DLL_SPEC WaypointMovementGenerator<Creature>
|
||||
: public MovementGeneratorMedium< Creature, WaypointMovementGenerator<Creature> >,
|
||||
public PathMovementBase<Creature, WaypointPath*>
|
||||
class TRINITY_DLL_SPEC WaypointMovementGenerator
|
||||
: public MovementGeneratorMedium< T, WaypointMovementGenerator<T> >, public PathMovementBase<T>
|
||||
{
|
||||
TimeTrackerSmall i_nextMoveTime;
|
||||
std::vector<bool> i_hasDone;
|
||||
public:
|
||||
WaypointMovementGenerator(Creature &) : i_nextMoveTime(0) {}
|
||||
~WaypointMovementGenerator() { ClearWaypoints(); }
|
||||
void Initialize(Creature &u)
|
||||
{
|
||||
i_nextMoveTime.Reset(0); // TODO: check the lower bound (0 is probably too small)
|
||||
u.StopMoving();
|
||||
LoadPath(u);
|
||||
}
|
||||
void Finalize(Creature &) {}
|
||||
void Reset(Creature &u) { ReloadPath(u); }
|
||||
bool Update(Creature &u, const uint32 &diff);
|
||||
public:
|
||||
WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true) :
|
||||
i_nextMoveTime(0), path_id(_path_id), repeating(_repeating), StopedByPlayer(false){}
|
||||
|
||||
void Initialize(T &);
|
||||
void Finalize(T &);
|
||||
void MovementInform(T &);
|
||||
void InitTraveller(T &, const WaypointData &);
|
||||
void GeneratePathId(T &);
|
||||
void Reset(T &unit);
|
||||
bool Update(T &, const uint32 &);
|
||||
bool GetDestination(float &x, float &y, float &z) const;
|
||||
MovementGeneratorType GetMovementGeneratorType() { return WAYPOINT_MOTION_TYPE; }
|
||||
|
||||
void MovementInform(Creature &);
|
||||
|
||||
MovementGeneratorType GetMovementGeneratorType() { return WAYPOINT_MOTION_TYPE; }
|
||||
|
||||
// now path movement implmementation
|
||||
void LoadPath(Creature &c);
|
||||
void ReloadPath(Creature &c) { ClearWaypoints(); LoadPath(c); }
|
||||
|
||||
// Player stoping creature
|
||||
bool IsStopedByPlayer() { return b_StopedByPlayer; }
|
||||
void SetStopedByPlayer(bool val) { b_StopedByPlayer = val; }
|
||||
|
||||
// statics
|
||||
static void Initialize(void);
|
||||
|
||||
bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x,y,z); return true; }
|
||||
private:
|
||||
void ClearWaypoints();
|
||||
bool b_StopedByPlayer;
|
||||
private:
|
||||
WaypointData node;
|
||||
uint32 i_currentNode, path_id;
|
||||
TimeTrackerSmall i_nextMoveTime;
|
||||
WaypointPath *waypoints;
|
||||
bool repeating, custom_path, ExecuteScript, StopedByPlayer;
|
||||
};
|
||||
|
||||
/** FlightPathMovementGenerator generates movement of the player for the paths
|
||||
@@ -135,6 +112,7 @@ public PathMovementBase<Player>
|
||||
inline bool HasArrived() const { return (i_currentNode >= i_path.Size()); }
|
||||
void SetCurrentNodeAfterTeleport();
|
||||
void SkipCurrentNode() { ++i_currentNode; }
|
||||
bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x,y,z); return true; }
|
||||
bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x,y,z); return true; }
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
+26
-2
@@ -1271,6 +1271,7 @@ void World::SetInitialWorldSettings()
|
||||
objmgr.LoadSpellScripts(); // must be after load Creature/Gameobject(Template/Data)
|
||||
objmgr.LoadGameObjectScripts(); // must be after load Creature/Gameobject(Template/Data)
|
||||
objmgr.LoadEventScripts(); // must be after load Creature/Gameobject(Template/Data)
|
||||
objmgr.LoadWaypointScripts();
|
||||
|
||||
sLog.outString( "Loading Scripts text locales..." ); // must be after Load*Scripts calls
|
||||
objmgr.LoadDbScriptStrings();
|
||||
@@ -1313,7 +1314,6 @@ void World::SetInitialWorldSettings()
|
||||
|
||||
///- Initilize static helper structures
|
||||
AIRegistry::Initialize();
|
||||
WaypointMovementGenerator<Creature>::Initialize();
|
||||
Player::InitVisibleBits();
|
||||
|
||||
///- Initialize MapManager
|
||||
@@ -2203,8 +2203,32 @@ void World::ScriptsProcess()
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SCRIPT_COMMAND_LOAD_PATH:
|
||||
{
|
||||
if(!source)
|
||||
{
|
||||
sLog.outError("SCRIPT_COMMAND_START_MOVE is tried to apply to NON-existing unit.");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if(!source->isType(TYPEMASK_UNIT))
|
||||
{
|
||||
sLog.outError("SCRIPT_COMMAND_START_MOVE source mover isn't unit (TypeId: %u), skipping.",source->GetTypeId());
|
||||
break;
|
||||
}
|
||||
|
||||
if(!WaypointMgr.GetPath(step.script->datalong))
|
||||
{
|
||||
sLog.outError("SCRIPT_COMMAND_START_MOVE source mover has an invallid path, skipping.", step.script->datalong2);
|
||||
break;
|
||||
}
|
||||
|
||||
dynamic_cast<Unit*>(source)->GetMotionMaster()->MovePath(step.script->datalong, step.script->datalong2);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
sLog.outError("Unknown script command %u called.",step.script->command);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -326,6 +326,7 @@ enum RealmZone
|
||||
#define SCRIPT_COMMAND_ACTIVATE_OBJECT 13 // source = unit, target=GO
|
||||
#define SCRIPT_COMMAND_REMOVE_AURA 14 // source (datalong2!=0) or target (datalong==0) unit, datalong = spell_id
|
||||
#define SCRIPT_COMMAND_CAST_SPELL 15 // source (datalong2!=0) or target (datalong==0) unit, datalong = spell_id
|
||||
#define SCRIPT_COMMAND_LOAD_PATH 16 // source = unit, path = datalong, repeatable datalong2
|
||||
|
||||
/// Storage class for commands issued for delayed execution
|
||||
struct CliCommandHolder
|
||||
|
||||
Reference in New Issue
Block a user