diff --git a/sql/characters.sql b/sql/characters.sql index c092b10fa..48fcd5fd3 100644 --- a/sql/characters.sql +++ b/sql/characters.sql @@ -21,7 +21,7 @@ DROP TABLE IF EXISTS `character_db_version`; CREATE TABLE `character_db_version` ( - `required_8469_01_characters_character_spell` bit(1) default NULL + `required_8505_01_characters_character_spell` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB'; -- diff --git a/sql/mangos.sql b/sql/mangos.sql index a5fdf2b3b..f6bf658d6 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -24,7 +24,7 @@ CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, `cache_id` int(10) default '0', - `required_8499_01_mangos_spell_elixir` bit(1) default NULL + `required_8521_01_mangos_spell_proc_event` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -9746,7 +9746,7 @@ INSERT INTO `playercreateinfo_action` VALUES (1,1,96,6603,0), (1,1,108,6603,0), (1,2,0,6603,0), -(1,2,1,20154,0), +(1,2,1,21084,0), (1,2,2,635,0), (1,2,9,59752,0), (1,2,10,159,128), @@ -9833,7 +9833,7 @@ INSERT INTO `playercreateinfo_action` VALUES (3,1,96,6603,0), (3,1,108,6603,0), (3,2,0,6603,0), -(3,2,1,20154,0), +(3,2,1,21084,0), (3,2,2,635,0), (3,2,3,20594,0), (3,2,4,2481,0), @@ -10295,7 +10295,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (1,2,9078,'Cloth'), (1,2,9116,'Shield'), (1,2,9125,'Generic'), -(1,2,20154,'Seal of Righteousness'), +(1,2,21084,'Seal of Righteousness'), (1,2,20597,'Sword Specialization'), (1,2,20598,'The Human Spirit'), (1,2,20599,'Diplomacy'), @@ -10882,7 +10882,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (3,2,9078,'Cloth'), (3,2,9116,'Shield'), (3,2,9125,'Generic'), -(3,2,20154,'Seal of Righteousness'), +(3,2,21084,'Seal of Righteousness'), (3,2,20594,'Stoneform'), (3,2,20595,'Gun Specialization'), (3,2,20596,'Frost Resistance'), @@ -13659,6 +13659,7 @@ INSERT INTO `spell_bonus_data` VALUES (20925, 0.09, 0, 0.056, 'Paladin - Holy Shield'), (31803, 0, 0.0156, 0.03, 'Paladin - Holy Vengeance'), (2812, 0.07, 0, 0.07, 'Paladin - Holy Wrath'), +(54158, 0.25, 0, 0, 'Paladin - Judgement'), (31898, 0.18, 0, 0.11, 'Paladin - Judgement of Blood Enemy'), (32220, 0.0594, 0, 0.0363,'Paladin - Judgement of Blood Self'), (20467, 0.25, 0, 0.16, 'Paladin - Judgement of Command'), @@ -17929,6 +17930,7 @@ INSERT INTO `spell_proc_event` VALUES (56344, 0x00000000, 9, 0x00004000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (56355, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000040, 0.000000, 0.000000, 0), (56364, 0x00000000, 3, 0x00000000, 0x01000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), +(56372, 0x00000000, 3, 0x00000000, 0x00000080, 0x00000000, 0x00004000, 0x00000000, 0.000000, 0.000000, 0), (56451, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 3), (56611, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0), (56612, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0), @@ -17942,6 +17944,8 @@ INSERT INTO `spell_proc_event` VALUES (56834, 0x00000000, 15, 0x00440000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (56835, 0x00000000, 15, 0x00440000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (57352, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00010154, 0x00000003, 0.000000, 0.000000, 45), +(57470, 0x00000000, 6, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), +(57472, 0x00000000, 6, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (57878, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0.000000, 0.000000, 0), (57880, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0.000000, 0.000000, 0), (57881, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0.000000, 0.000000, 0), diff --git a/sql/mangos_spell_check.sql b/sql/mangos_spell_check.sql index 7b1bc2c7f..a6b8c3cde 100644 --- a/sql/mangos_spell_check.sql +++ b/sql/mangos_spell_check.sql @@ -308,8 +308,11 @@ INSERT INTO spell_check (spellid,SpellFamilyName,SpellFamilyMaskA,SpellFamilyMas (53196, 7,0x0000000000000000,0x00000100, -1, -1, -1, 3, -1,-1,'Starfall', 'Spell::EffectDummy'), (53197, 7,0x0000000000000000,0x00000100, -1, -1, -1, 3, -1,-1,'Starfall', 'Spell::EffectDummy'), (53198, 7,0x0000000000000000,0x00000100, -1, -1, -1, 3, -1,-1,'Starfall', 'Spell::EffectDummy'), +(53271,-1, -1, -1, -1, -1, -1, 3, -1,-1,'Master''s Call', 'Spell::EffectDummy'), +(53271,-1, -1, -1, -1, -1, -1, 77, -1,-1,'Master''s Call', 'Spell::EffectScriptEffect'), (53341, 0, -1, -1, -1, -1, -1, 3, -1,-1,'Rune of Cinderglacier', 'Spell::EffectDummy'), (53343, 0, -1, -1, -1, -1, -1, 3, -1,-1,'Rune of Razorice', 'Spell::EffectDummy'), +(54216,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Master''s Call', 'Spell::EffectDummy'), (54586,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Runeforging Credit', 'Spell::EffectDummy'), (54824,-1, -1, -1, -1, -1, -1, -1, 4,-1,'Glyph of Swiftmend', 'Spell::EffectHeal'), (54861,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Nitro Boosts', 'Spell::EffectDummy'), @@ -335,6 +338,7 @@ INSERT INTO spell_check (spellid,SpellFamilyName,SpellFamilyMaskA,SpellFamilyMas (61491, 0, -1, -1, -1, -1, -1, 2, -1,-1,'Intercept', 'Spell::EffectSchoolDMG'), (61507, 9, -1, -1, -1, -1, -1, 3, -1,-1,'Disengage', 'Spell::EffectDummy'), (61508,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Disengage', 'Spell::EffectDummy'), +(62305,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Master''s Call', 'Spell::EffectScriptEffect'), (63375,-1, -1, -1, -1, -1, -1, 30, -1,-1,'Improved Stormstrike', 'Spell::EffectEnergize'), /* sorted by spell names */ diff --git a/sql/updates/8504_01_mangos_playercreateinfo_spell.sql b/sql/updates/8504_01_mangos_playercreateinfo_spell.sql new file mode 100644 index 000000000..44430211f --- /dev/null +++ b/sql/updates/8504_01_mangos_playercreateinfo_spell.sql @@ -0,0 +1,5 @@ +ALTER TABLE db_version CHANGE COLUMN required_8499_01_mangos_spell_elixir required_8504_01_mangos_playercreateinfo_spell bit; + +UPDATE `playercreateinfo_spell` + SET `spell` = 21084 + WHERE `spell` = 20154; diff --git a/sql/updates/8504_02_mangos_playercreateinfo_action.sql b/sql/updates/8504_02_mangos_playercreateinfo_action.sql new file mode 100644 index 000000000..31d561f07 --- /dev/null +++ b/sql/updates/8504_02_mangos_playercreateinfo_action.sql @@ -0,0 +1,5 @@ +ALTER TABLE db_version CHANGE COLUMN required_8504_01_mangos_playercreateinfo_spell required_8504_02_mangos_playercreateinfo_action bit; + +UPDATE `playercreateinfo_action` + SET `action` = 21084 + WHERE `action` = 20154 AND `type` = 0; diff --git a/sql/updates/8505_01_characters_character_spell.sql b/sql/updates/8505_01_characters_character_spell.sql new file mode 100644 index 000000000..51ff4c66b --- /dev/null +++ b/sql/updates/8505_01_characters_character_spell.sql @@ -0,0 +1,3 @@ +ALTER TABLE character_db_version CHANGE COLUMN required_8469_01_characters_character_spell required_8505_01_characters_character_spell bit; + +UPDATE character_spell SET active=1 WHERE spell=16857; diff --git a/sql/updates/8511_01_mangos_spell_proc_event.sql b/sql/updates/8511_01_mangos_spell_proc_event.sql new file mode 100644 index 000000000..d4c9d97a6 --- /dev/null +++ b/sql/updates/8511_01_mangos_spell_proc_event.sql @@ -0,0 +1,7 @@ +ALTER TABLE db_version CHANGE COLUMN required_8504_02_mangos_playercreateinfo_action required_8511_01_mangos_spell_proc_event bit; + +DELETE FROM `spell_proc_event` WHERE `entry` IN (57470, 57472); + +INSERT INTO spell_proc_event VALUES +(57470, 0x00000000, 6, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), +(57472, 0x00000000, 6, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0); diff --git a/sql/updates/8514_01_mangos_spell_bonus_data.sql b/sql/updates/8514_01_mangos_spell_bonus_data.sql new file mode 100644 index 000000000..8549ee6df --- /dev/null +++ b/sql/updates/8514_01_mangos_spell_bonus_data.sql @@ -0,0 +1,6 @@ +ALTER TABLE db_version CHANGE COLUMN required_8511_01_mangos_spell_proc_event required_8514_01_mangos_spell_bonus_data bit; + +DELETE FROM `spell_bonus_data` WHERE `entry` IN (54158); + +INSERT INTO `spell_bonus_data` VALUES +(54158, 0.25, 0, 0, 'Paladin - Judgement'); diff --git a/sql/updates/8521_01_mangos_spell_proc_event.sql b/sql/updates/8521_01_mangos_spell_proc_event.sql new file mode 100644 index 000000000..8ebdaac96 --- /dev/null +++ b/sql/updates/8521_01_mangos_spell_proc_event.sql @@ -0,0 +1,6 @@ +ALTER TABLE db_version CHANGE COLUMN required_8514_01_mangos_spell_bonus_data required_8521_01_mangos_spell_proc_event bit; + +DELETE FROM `spell_proc_event` WHERE `entry` = 56372; + +INSERT INTO `spell_proc_event` VALUES +(56372, 0x00, 3, 0x00000000, 0x00000080, 0x00000000, 0x00004000, 0x00000000, 0.000000, 0.000000, 0); diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index 8463f8149..cd09ce4a8 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -107,6 +107,12 @@ pkgdata_DATA = \ 8488_02_mangos_spell_bonus_data.sql \ 8498_01_mangos_spell_proc_event.sql \ 8499_01_mangos_spell_elixir.sql \ + 8504_01_mangos_playercreateinfo_spell.sql \ + 8504_02_mangos_playercreateinfo_action.sql \ + 8505_01_characters_character_spell.sql \ + 8511_01_mangos_spell_proc_event.sql \ + 8514_01_mangos_spell_bonus_data.sql \ + 8521_01_mangos_spell_proc_event.sql \ README ## Additional files to include when running 'make dist' @@ -194,4 +200,10 @@ EXTRA_DIST = \ 8488_02_mangos_spell_bonus_data.sql \ 8498_01_mangos_spell_proc_event.sql \ 8499_01_mangos_spell_elixir.sql \ + 8504_01_mangos_playercreateinfo_spell.sql \ + 8504_02_mangos_playercreateinfo_action.sql \ + 8505_01_characters_character_spell.sql \ + 8511_01_mangos_spell_proc_event.sql \ + 8514_01_mangos_spell_bonus_data.sql \ + 8521_01_mangos_spell_proc_event.sql \ README diff --git a/src/framework/GameSystem/NGrid.h b/src/framework/GameSystem/NGrid.h index 469e47fb0..7393c3ddf 100644 --- a/src/framework/GameSystem/NGrid.h +++ b/src/framework/GameSystem/NGrid.h @@ -79,8 +79,19 @@ class MANGOS_DLL_DECL NGrid i_GridInfo = GridInfo(expiry, unload); } - const GridType& operator()(unsigned short x, unsigned short y) const { return i_cells[x][y]; } - GridType& operator()(unsigned short x, unsigned short y) { return i_cells[x][y]; } + const GridType& operator()(unsigned short x, unsigned short y) const + { + ASSERT(x < N); + ASSERT(y < N); + return i_cells[x][y]; + } + + GridType& operator()(unsigned short x, unsigned short y) + { + ASSERT(x < N); + ASSERT(y < N); + return i_cells[x][y]; + } const uint32& GetGridId(void) const { return i_gridId; } void SetGridId(const uint32 id) const { i_gridId = id; } @@ -108,12 +119,12 @@ class MANGOS_DLL_DECL NGrid template void AddWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl) { - i_cells[x][y].AddWorldObject(obj, hdl); + getGridType(x, y).AddWorldObject(obj, hdl); } template void RemoveWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl) { - i_cells[x][y].RemoveWorldObject(obj, hdl); + getGridType(x, y).RemoveWorldObject(obj, hdl); } template void Visit(TypeContainerVisitor > &visitor) @@ -125,7 +136,7 @@ class MANGOS_DLL_DECL NGrid template void Visit(const uint32 &x, const uint32 &y, TypeContainerVisitor > &visitor) { - i_cells[x][y].Visit(visitor); + getGridType(x, y).Visit(visitor); } unsigned int ActiveObjectsInGrid(void) const @@ -139,26 +150,33 @@ class MANGOS_DLL_DECL NGrid template const SPECIFIC_OBJECT* GetGridObject(const uint32 x, const uint32 y, OBJECT_HANDLE hdl) const { - return i_cells[x][y].template GetGridObject(hdl); + return getGridType(x, y).template GetGridObject(hdl); } template SPECIFIC_OBJECT* GetGridObject(const uint32 x, const uint32 y, OBJECT_HANDLE hdl) { - return i_cells[x][y].template GetGridObject(hdl); + return getGridType(x, y).template GetGridObject(hdl); } template bool AddGridObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl) { - return i_cells[x][y].AddGridObject(hdl, obj); + return getGridType(x, y).AddGridObject(hdl, obj); } template bool RemoveGridObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl) { - return i_cells[x][y].RemoveGridObject(obj, hdl); + return getGridType(x, y).RemoveGridObject(obj, hdl); } private: + GridType& getGridType(const uint32& x, const uint32& y) + { + ASSERT(x < N); + ASSERT(y < N); + return i_cells[x][y]; + } + uint32 i_gridId; GridInfo i_GridInfo; GridReference > i_Reference; diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index 7677dfdfa..2b816aa53 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -605,7 +605,7 @@ void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement) MaNGOS::PlayerDistWorker > say_worker(GetPlayer(),sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY),say_do); TypeContainerVisitor >, WorldTypeMapContainer > message(say_worker); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *GetPlayer()->GetMap()); + cell_lock->Visit(cell_lock, message, *GetPlayer()->GetMap(), *GetPlayer(), sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY)); } WorldPacket data(SMSG_ACHIEVEMENT_EARNED, 8+4+8); diff --git a/src/game/Cell.h b/src/game/Cell.h index 32dec557f..8d310ba19 100644 --- a/src/game/Cell.h +++ b/src/game/Cell.h @@ -25,6 +25,7 @@ #include class Map; +class WorldObject; enum District { @@ -42,6 +43,26 @@ enum District template struct CellLock; +struct MANGOS_DLL_DECL CellArea +{ + CellArea() : right_offset(0), left_offset(0), upper_offset(0), lower_offset(0) {} + CellArea(int right, int left, int upper, int lower) : right_offset(right), left_offset(left), upper_offset(upper), lower_offset(lower) {} + bool operator!() const { return !right_offset && !left_offset && !upper_offset && !lower_offset; } + + void ResizeBorders(CellPair& begin_cell, CellPair& end_cell) const + { + begin_cell << left_offset; + begin_cell -= lower_offset; + end_cell >> right_offset; + end_cell += upper_offset; + } + + int right_offset; + int left_offset; + int upper_offset; + int lower_offset; +}; + struct MANGOS_DLL_DECL Cell { Cell() { data.All = 0; } @@ -131,15 +152,21 @@ struct MANGOS_DLL_DECL Cell { unsigned grid_x : 6; unsigned grid_y : 6; - unsigned cell_x : 4; - unsigned cell_y : 4; + unsigned cell_x : 6; + unsigned cell_y : 6; unsigned nocreate : 1; - unsigned reserved : 11; + unsigned reserved : 7; } Part; uint32 All; } data; template void Visit(const CellLock &, TypeContainerVisitor &visitor, Map &) const; + template void Visit(const CellLock &, TypeContainerVisitor &visitor, Map &m, const WorldObject &obj, float radius) const; + + static CellArea CalculateCellArea(const WorldObject &obj, float radius); + +private: + template void VisitCircle(const CellLock &, TypeContainerVisitor &, Map &, const CellPair& , const CellPair& ) const; }; template diff --git a/src/game/CellImpl.h b/src/game/CellImpl.h index 7302820bb..f1d8732b3 100644 --- a/src/game/CellImpl.h +++ b/src/game/CellImpl.h @@ -127,4 +127,163 @@ Cell::Visit(const CellLock &l, TypeContainerVisitor &vi } } } + +inline int CellHelper(const float radius) +{ + if(radius < 1.0f) + return 0; + + return (int)ceilf(radius/SIZE_OF_GRID_CELL); +} + +inline CellArea Cell::CalculateCellArea(const WorldObject &obj, float radius) +{ + if(radius <= 0.0f) + return CellArea(); + + //we should increase search radius by object's radius, otherwise + //we could have problems with huge creatures, which won't attack nearest players etc + radius += obj.GetObjectSize(); + //lets calculate object coord offsets from cell borders. + //TODO: add more correct/generic method for this task + const float x_offset = (obj.GetPositionX() - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL; + const float y_offset = (obj.GetPositionY() - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL; + + const float x_val = floor(x_offset + CENTER_GRID_CELL_ID + 0.5f); + const float y_val = floor(y_offset + CENTER_GRID_CELL_ID + 0.5f); + + const float x_off = (x_offset - x_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL; + const float y_off = (y_offset - y_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL; + + const float tmp_diff = radius - CENTER_GRID_CELL_OFFSET; + //lets calculate upper/lower/right/left corners for cell search + int right = CellHelper(tmp_diff + x_off); + int left = CellHelper(tmp_diff - x_off); + int upper = CellHelper(tmp_diff + y_off); + int lower = CellHelper(tmp_diff - y_off); + + return CellArea(right, left, upper, lower); +} + +template +inline void +Cell::Visit(const CellLock &l, TypeContainerVisitor &visitor, Map &m, const WorldObject &obj, float radius) 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; + + //no jokes here... Actually placing ASSERT() here was good idea, but + //we had some problems with DynamicObjects, which pass radius = 0.0f (DB issue?) + //maybe it is better to just return when radius <= 0.0f? + if(radius <= 0.0f) + { + m.Visit(l, visitor); + return; + } + //lets limit the upper value for search radius + if(radius > 333.0f) + radius = 333.0f; + + //lets calculate object coord offsets from cell borders. + CellArea area = Cell::CalculateCellArea(obj, radius); + //if radius fits inside standing cell + if(!area) + { + m.Visit(l, visitor); + return; + } + + CellPair begin_cell = standing_cell; + CellPair end_cell = standing_cell; + + area.ResizeBorders(begin_cell, end_cell); + //visit all cells, found in CalculateCellArea() + //if radius is known to reach cell area more than 4x4 then we should call optimized VisitCircle + //currently this technique works with MAX_NUMBER_OF_CELLS 16 and higher, with lower values + //there are nothing to optimize because SIZE_OF_GRID_CELL is too big... + if(((end_cell.x_coord - begin_cell.x_coord) > 4) && ((end_cell.y_coord - begin_cell.y_coord) > 4)) + { + VisitCircle(l, visitor, m, begin_cell, end_cell); + return; + } + + //ALWAYS visit standing cell first!!! Since we deal with small radiuses + //it is very essential to call visitor for standing cell firstly... + m.Visit(l, visitor); + + // 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); + //lets skip standing cell since we already visited it + if(cell_pair != standing_cell) + { + Cell r_zone(cell_pair); + r_zone.data.Part.nocreate = l->data.Part.nocreate; + CellLock lock(r_zone, cell_pair); + m.Visit(lock, visitor); + } + } + } +} + +template +inline void +Cell::VisitCircle(const CellLock &l, TypeContainerVisitor &visitor, Map &m, const CellPair& begin_cell, const CellPair& end_cell) const +{ + //here is an algorithm for 'filling' circum-squared octagon + uint32 x_shift = (uint32)ceilf((end_cell.x_coord - begin_cell.x_coord) * 0.3f - 0.5f); + //lets calculate x_start/x_end coords for central strip... + const uint32 x_start = begin_cell.x_coord + x_shift; + const uint32 x_end = end_cell.x_coord - x_shift; + + //visit central strip with constant width... + for(uint32 x = x_start; x <= x_end; ++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(r_zone, cell_pair); + m.Visit(lock, visitor); + } + } + + //if x_shift == 0 then we have too small cell area, which were already + //visited at previous step, so just return from procedure... + if(x_shift == 0) + return; + + uint32 y_start = end_cell.y_coord; + uint32 y_end = begin_cell.y_coord; + //now we are visiting borders of an octagon... + for (uint32 step = 1; step <= (x_start - begin_cell.x_coord); ++step) + { + //each step reduces strip height by 2 cells... + y_end += 1; + y_start -= 1; + for (uint32 y = y_start; y >= y_end; --y) + { + //we visit cells symmetrically from both sides, heading from center to sides and from up to bottom + //e.g. filling 2 trapezoids after filling central cell strip... + CellPair cell_pair_left(x_start - step, y); + Cell r_zone_left(cell_pair_left); + r_zone_left.data.Part.nocreate = l->data.Part.nocreate; + CellLock lock_left(r_zone_left, cell_pair_left); + m.Visit(lock_left, visitor); + + //right trapezoid cell visit + CellPair cell_pair_right(x_end + step, y); + Cell r_zone_right(cell_pair_right); + r_zone_right.data.Part.nocreate = l->data.Part.nocreate; + CellLock lock_right(r_zone_right, cell_pair_right); + m.Visit(lock_right, visitor); + } + } +} + #endif diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cpp index f6bd8db92..edd647ee4 100644 --- a/src/game/ChatHandler.cpp +++ b/src/game/ChatHandler.cpp @@ -584,7 +584,7 @@ void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data ) MaNGOS::PlayerDistWorker > emote_worker(GetPlayer(),sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),emote_do); TypeContainerVisitor >, WorldTypeMapContainer > message(emote_worker); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *GetPlayer()->GetMap()); + cell_lock->Visit(cell_lock, message, *GetPlayer()->GetMap(), *GetPlayer(), sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE)); GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit); diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 4f6825066..00ce44097 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -534,7 +534,7 @@ void Creature::DoFleeToGetAssistance() TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *GetMap()); + cell_lock->Visit(cell_lock, grid_creature_searcher, *GetMap(), *this, radius); SetNoSearchAssistance(true); if(!pCreature) @@ -1776,7 +1776,7 @@ void Creature::CallAssistance() TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *GetMap()); + cell_lock->Visit(cell_lock, grid_creature_searcher, *GetMap(), *this, radius); } if (!assistList.empty()) @@ -1810,7 +1810,7 @@ void Creature::CallForHelp(float fRadius) TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(worker); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *GetMap()); + cell_lock->Visit(cell_lock, grid_creature_searcher, *GetMap(), *this, fRadius); } bool Creature::CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction /*= true*/) const diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp index 936045f6b..4db0796b2 100644 --- a/src/game/CreatureEventAI.cpp +++ b/src/game/CreatureEventAI.cpp @@ -1214,7 +1214,7 @@ Unit* CreatureEventAI::DoSelectLowestHpFriendly(float range, uint32 MinHPDiff) TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_unit_searcher, *m_creature->GetMap()); + cell_lock->Visit(cell_lock, grid_unit_searcher, *m_creature->GetMap(), *m_creature, range); return pUnit; } @@ -1231,7 +1231,7 @@ void CreatureEventAI::DoFindFriendlyCC(std::list& _list, float range) TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *m_creature->GetMap()); + cell_lock->Visit(cell_lock, grid_creature_searcher, *m_creature->GetMap(), *m_creature, range); } void CreatureEventAI::DoFindFriendlyMissingBuff(std::list& _list, float range, uint32 spellid) @@ -1247,7 +1247,7 @@ void CreatureEventAI::DoFindFriendlyMissingBuff(std::list& _list, flo TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *m_creature->GetMap()); + cell_lock->Visit(cell_lock, grid_creature_searcher, *m_creature->GetMap(), *m_creature, range); } //********************************* diff --git a/src/game/DynamicObject.cpp b/src/game/DynamicObject.cpp index bb775038b..92db7e25b 100644 --- a/src/game/DynamicObject.cpp +++ b/src/game/DynamicObject.cpp @@ -125,8 +125,8 @@ void DynamicObject::Update(uint32 p_time) TypeContainerVisitor grid_object_notifier(notifier); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_object_notifier, *GetMap()); - cell_lock->Visit(cell_lock, grid_object_notifier, *GetMap()); + cell_lock->Visit(cell_lock, world_object_notifier, *GetMap(), *this, m_radius); + cell_lock->Visit(cell_lock, grid_object_notifier, *GetMap(), *this, m_radius); } if(deleteThis) diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index 794e11ca1..d88193726 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -319,13 +319,13 @@ void GameObject::Update(uint32 /*p_time*/) CellLock cell_lock(cell, p); TypeContainerVisitor, GridTypeMapContainer > grid_object_checker(checker); - cell_lock->Visit(cell_lock, grid_object_checker, *GetMap()); + cell_lock->Visit(cell_lock, grid_object_checker, *GetMap(), *this, radius); // or unfriendly player/pet if(!ok) { TypeContainerVisitor, WorldTypeMapContainer > world_object_checker(checker); - cell_lock->Visit(cell_lock, world_object_checker, *GetMap()); + cell_lock->Visit(cell_lock, world_object_checker, *GetMap(), *this, radius); } } else // environmental trap @@ -340,7 +340,7 @@ void GameObject::Update(uint32 /*p_time*/) CellLock cell_lock(cell, p); TypeContainerVisitor, WorldTypeMapContainer > world_object_checker(checker); - cell_lock->Visit(cell_lock, world_object_checker, *GetMap()); + cell_lock->Visit(cell_lock, world_object_checker, *GetMap(), *this, radius); ok = p_ok; } @@ -784,7 +784,7 @@ void GameObject::TriggeringLinkedGameObject( uint32 trapEntry, Unit* target) TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *GetMap()); + cell_lock->Visit(cell_lock, object_checker, *GetMap(), *target, range); } // found correct GO @@ -806,7 +806,7 @@ GameObject* GameObject::LookupFishingHoleAround(float range) CellLock cell_lock(cell, p); TypeContainerVisitor, GridTypeMapContainer > grid_object_checker(checker); - cell_lock->Visit(cell_lock, grid_object_checker, *GetMap()); + cell_lock->Visit(cell_lock, grid_object_checker, *GetMap(), *this, range); return ok; } @@ -1031,7 +1031,8 @@ void GameObject::Use(Unit* user) //fish catched player->UpdateFishingSkill(); - GameObject* ok = LookupFishingHoleAround(DEFAULT_VISIBILITY_DISTANCE); + //TODO: find reasonable value for fishing hole search + GameObject* ok = LookupFishingHoleAround(20.0f + CONTACT_DISTANCE); if (ok) { player->SendLoot(ok->GetGUID(),LOOT_FISHINGHOLE); diff --git a/src/game/GridDefines.h b/src/game/GridDefines.h index 6553bebf3..7d57814fb 100644 --- a/src/game/GridDefines.h +++ b/src/game/GridDefines.h @@ -41,7 +41,7 @@ class Player; #define MIN_GRID_DELAY (MINUTE*IN_MILISECONDS) #define MIN_MAP_UPDATE_DELAY 50 -#define MAX_NUMBER_OF_CELLS 4 +#define MAX_NUMBER_OF_CELLS 8 #define SIZE_OF_GRID_CELL (SIZE_OF_GRIDS/MAX_NUMBER_OF_CELLS) #define CENTER_GRID_CELL_ID (MAX_NUMBER_OF_CELLS*MAX_NUMBER_OF_GRIDS/2) @@ -86,26 +86,34 @@ struct MANGOS_DLL_DECL CoordPair void operator<<(const uint32 val) { - if( x_coord >= val ) + if( x_coord > val ) x_coord -= val; + else + x_coord = 0; } void operator>>(const uint32 val) { if( x_coord+val < LIMIT ) x_coord += val; + else + x_coord = LIMIT - 1; } void operator-=(const uint32 val) { - if( y_coord >= val ) + if( y_coord > val ) y_coord -= val; + else + y_coord = 0; } void operator+=(const uint32 val) { if( y_coord+val < LIMIT ) y_coord += val; + else + y_coord = LIMIT - 1; } uint32 x_coord; diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 0206c5ae7..e37c82ba3 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -190,6 +190,7 @@ bool ChatHandler::HandleReloadConfigCommand(const char* /*args*/) { sLog.outString( "Re-Loading config settings..." ); sWorld.LoadConfigSettings(true); + MapManager::Instance().InitializeVisibilityDistanceInfo(); SendGlobalSysMessage("World config settings reloaded."); return true; } diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 9f445d128..35dd3d744 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -41,6 +41,7 @@ #define DEFAULT_GRID_EXPIRY 300 #define MAX_GRID_LOAD_TIME 50 +#define MAX_CREATURE_ATTACK_RADIUS (45.0f * sWorld.getRate(RATE_CREATURE_AGGRO)) GridState* si_GridStates[MAX_GRID_STATE]; @@ -198,7 +199,8 @@ Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _par : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0), m_activeNonPlayersIter(m_activeNonPlayers.end()), - i_gridExpiry(expiry), m_parentMap(_parent ? _parent : this) + i_gridExpiry(expiry), m_parentMap(_parent ? _parent : this), + m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE) { for(unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx) { @@ -209,6 +211,15 @@ Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _par setNGrid(NULL, idx, j); } } + + //lets initialize visibility distance for map + Map::InitVisibilityDistance(); +} + +void Map::InitVisibilityDistance() +{ + //init visibility for continents + m_VisibleDistance = sWorld.GetMaxVisibleDistanceOnContinents(); } // Template specialization of utility methods @@ -346,8 +357,8 @@ Map::EnsureGridCreated(const GridPair &p) getNGrid(p.x_coord, p.y_coord)->SetGridState(GRID_STATE_IDLE); //z coord - int gx=63-p.x_coord; - int gy=63-p.y_coord; + int gx = (MAX_NUMBER_OF_GRIDS - 1) - p.x_coord; + int gy = (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord; if(!GridMaps[gx][gy]) LoadMapAndVMap(gx,gy); @@ -491,7 +502,7 @@ void Map::MessageBroadcast(Player *player, WorldPacket *msg, bool to_self) MaNGOS::MessageDeliverer post_man(*player, msg, to_self); TypeContainerVisitor message(post_man); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *this); + cell_lock->Visit(cell_lock, message, *this, *player, GetVisibilityDistance()); } void Map::MessageBroadcast(WorldObject *obj, WorldPacket *msg) @@ -511,10 +522,12 @@ void Map::MessageBroadcast(WorldObject *obj, WorldPacket *msg) if( !loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y)) ) return; + //TODO: currently on continents when Visibility.Distance.InFlight > Visibility.Distance.Continents + //we have alot of blinking mobs because monster move packet send is broken... MaNGOS::ObjectMessageDeliverer post_man(*obj,msg); TypeContainerVisitor message(post_man); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *this); + cell_lock->Visit(cell_lock, message, *this, *obj, GetVisibilityDistance()); } void Map::MessageDistBroadcast(Player *player, WorldPacket *msg, float dist, bool to_self, bool own_team_only) @@ -537,7 +550,7 @@ void Map::MessageDistBroadcast(Player *player, WorldPacket *msg, float dist, boo MaNGOS::MessageDistDeliverer post_man(*player, msg, dist, to_self, own_team_only); TypeContainerVisitor message(post_man); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *this); + cell_lock->Visit(cell_lock, message, *this, *player, dist); } void Map::MessageDistBroadcast(WorldObject *obj, WorldPacket *msg, float dist) @@ -557,10 +570,10 @@ void Map::MessageDistBroadcast(WorldObject *obj, WorldPacket *msg, float dist) if( !loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y)) ) return; - MaNGOS::ObjectMessageDistDeliverer post_man(*obj, msg,dist); + MaNGOS::ObjectMessageDistDeliverer post_man(*obj, msg, dist); TypeContainerVisitor message(post_man); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *this); + cell_lock->Visit(cell_lock, message, *this, *obj, dist); } bool Map::loaded(const GridPair &p) const @@ -605,8 +618,9 @@ void Map::Update(const uint32 &t_diff) // the overloaded operators handle range checking // so ther's no need for range checking inside the loop CellPair begin_cell(standing_cell), end_cell(standing_cell); - begin_cell << 1; begin_cell -= 1; // upper left - end_cell >> 1; end_cell += 1; // lower right + //lets update mobs/objects in ALL visible cells around player! + CellArea area = Cell::CalculateCellArea(*plr, GetVisibilityDistance()); + area.ResizeBorders(begin_cell, end_cell); for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x) { @@ -1044,8 +1058,9 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool pForce) delete getNGrid(x, y); setNGrid(NULL, x, y); } - int gx=63-x; - int gy=63-y; + + int gx = (MAX_NUMBER_OF_GRIDS - 1) - x; + int gy = (MAX_NUMBER_OF_GRIDS - 1) - y; // delete grid map, but don't delete if it is from parent map (and thus only reference) //+++if (GridMaps[gx][gy]) don't check for GridMaps[gx][gy], we might have to unload vmaps @@ -1921,7 +1936,7 @@ void Map::UpdateObjectVisibility( WorldObject* obj, Cell cell, CellPair cellpair MaNGOS::VisibleChangesNotifier notifier(*obj); TypeContainerVisitor player_notifier(notifier); CellLock cell_lock(cell, cellpair); - cell_lock->Visit(cell_lock, player_notifier, *this); + cell_lock->Visit(cell_lock, player_notifier, *this, *obj, GetVisibilityDistance()); } void Map::UpdatePlayerVisibility( Player* player, Cell cell, CellPair cellpair ) @@ -1932,7 +1947,7 @@ void Map::UpdatePlayerVisibility( Player* player, Cell cell, CellPair cellpair ) TypeContainerVisitor player_notifier(pl_notifier); CellLock cell_lock(cell, cellpair); - cell_lock->Visit(cell_lock, player_notifier, *this); + cell_lock->Visit(cell_lock, player_notifier, *this, *player, GetVisibilityDistance()); } void Map::UpdateObjectsVisibilityFor( Player* player, Cell cell, CellPair cellpair ) @@ -1944,8 +1959,8 @@ void Map::UpdateObjectsVisibilityFor( Player* player, Cell cell, CellPair cellpa TypeContainerVisitor world_notifier(notifier); TypeContainerVisitor grid_notifier(notifier); CellLock cell_lock(cell, cellpair); - cell_lock->Visit(cell_lock, world_notifier, *this); - cell_lock->Visit(cell_lock, grid_notifier, *this); + cell_lock->Visit(cell_lock, world_notifier, *this, *player, GetVisibilityDistance()); + cell_lock->Visit(cell_lock, grid_notifier, *this, *player, GetVisibilityDistance()); // send data notifier.Notify(); @@ -1960,8 +1975,8 @@ void Map::PlayerRelocationNotify( Player* player, Cell cell, CellPair cellpair ) TypeContainerVisitor p2grid_relocation(relocationNotifier); TypeContainerVisitor p2world_relocation(relocationNotifier); - cell_lock->Visit(cell_lock, p2grid_relocation, *this); - cell_lock->Visit(cell_lock, p2world_relocation, *this); + cell_lock->Visit(cell_lock, p2grid_relocation, *this, *player, MAX_CREATURE_ATTACK_RADIUS); + cell_lock->Visit(cell_lock, p2world_relocation, *this, *player, MAX_CREATURE_ATTACK_RADIUS); } void Map::CreatureRelocationNotify(Creature *creature, Cell cell, CellPair cellpair) @@ -1974,8 +1989,8 @@ void Map::CreatureRelocationNotify(Creature *creature, Cell cell, CellPair cellp TypeContainerVisitor c2world_relocation(relocationNotifier); TypeContainerVisitor c2grid_relocation(relocationNotifier); - cell_lock->Visit(cell_lock, c2world_relocation, *this); - cell_lock->Visit(cell_lock, c2grid_relocation, *this); + cell_lock->Visit(cell_lock, c2world_relocation, *this, *creature, MAX_CREATURE_ATTACK_RADIUS); + cell_lock->Visit(cell_lock, c2grid_relocation, *this, *creature, MAX_CREATURE_ATTACK_RADIUS); } void Map::SendInitSelf( Player * player ) @@ -2145,12 +2160,20 @@ void Map::SendToPlayers(WorldPacket const* data) const bool Map::ActiveObjectsNearGrid(uint32 x, uint32 y) const { + ASSERT(x < MAX_NUMBER_OF_GRIDS); + ASSERT(y < MAX_NUMBER_OF_GRIDS); + CellPair cell_min(x*MAX_NUMBER_OF_CELLS, y*MAX_NUMBER_OF_CELLS); CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS); - cell_min << 2; - cell_min -= 2; - cell_max >> 2; - cell_max += 2; + + //we must find visible range in cells so we unload only non-visible cells... + float viewDist = GetVisibilityDistance(); + int cell_range = (int)ceilf(viewDist / SIZE_OF_GRID_CELL) + 1; + + cell_min << cell_range; + cell_min -= cell_range; + cell_max >> cell_range; + cell_max += cell_range; for(MapRefManager::const_iterator iter = m_mapRefManager.begin(); iter != m_mapRefManager.end(); ++iter) { @@ -2234,6 +2257,9 @@ InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 Spaw m_resetAfterUnload(false), m_unloadWhenEmpty(false), i_data(NULL), i_script_id(0) { + //lets initialize visibility distance for dungeons + InstanceMap::InitVisibilityDistance(); + // the timer is started by default, and stopped when the first player joins // this make sure it gets unloaded if for some reason no player joins m_unloadTimer = std::max(sWorld.getConfig(CONFIG_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY); @@ -2248,6 +2274,12 @@ InstanceMap::~InstanceMap() } } +void InstanceMap::InitVisibilityDistance() +{ + //init visibility distance for instances + m_VisibleDistance = sWorld.GetMaxVisibleDistanceInInstances(); +} + /* Do map specific checks to see if the player can enter */ @@ -2570,12 +2602,20 @@ uint32 InstanceMap::GetMaxPlayers() const BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent) : Map(id, expiry, InstanceId, DUNGEON_DIFFICULTY_NORMAL, _parent) { + //lets initialize visibility distance for BG/Arenas + BattleGroundMap::InitVisibilityDistance(); } BattleGroundMap::~BattleGroundMap() { } +void BattleGroundMap::InitVisibilityDistance() +{ + //init visibility distance for BG/Arenas + m_VisibleDistance = sWorld.GetMaxVisibleDistanceInBGArenas(); +} + bool BattleGroundMap::CanEnter(Player * player) { if(player->GetMapRef().getTarget() == this) diff --git a/src/game/Map.h b/src/game/Map.h index 2b60a3fee..1227e4277 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -279,6 +279,10 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj void MessageDistBroadcast(Player *, WorldPacket *, float dist, bool to_self, bool own_team_only = false); void MessageDistBroadcast(WorldObject *, WorldPacket *, float dist); + float GetVisibilityDistance() const { return m_VisibleDistance; } + //function for setting up visibility distance for maps on per-type/per-Id basis + virtual void InitVisibilityDistance(); + void PlayerRelocation(Player *, float x, float y, float z, float angl); void CreatureRelocation(Creature *creature, float x, float y, float, float); @@ -424,7 +428,6 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj GridMap *GetGrid(float x, float y); void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; } - //uint64 CalculateGridMask(const uint32 &y) const; void SendInitSelf( Player * player ); @@ -451,6 +454,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj NGridType* getNGrid(uint32 x, uint32 y) const { + ASSERT(x < MAX_NUMBER_OF_GRIDS); + ASSERT(y < MAX_NUMBER_OF_GRIDS); return i_grids[x][y]; } @@ -470,6 +475,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj uint32 i_id; uint32 i_InstanceId; uint32 m_unloadTimer; + float m_VisibleDistance; MapRefManager m_mapRefManager; MapRefManager::iterator m_mapRefIter; @@ -557,6 +563,8 @@ class MANGOS_DLL_SPEC InstanceMap : public Map void SendResetWarnings(uint32 timeLeft) const; void SetResetSchedule(bool on); uint32 GetMaxPlayers() const; + + virtual void InitVisibilityDistance(); private: bool m_resetAfterUnload; bool m_unloadWhenEmpty; @@ -575,6 +583,8 @@ class MANGOS_DLL_SPEC BattleGroundMap : public Map bool CanEnter(Player* player); void SetUnload(); void UnloadAll(bool pForce); + + virtual void InitVisibilityDistance(); }; /*inline diff --git a/src/game/MapInstanced.cpp b/src/game/MapInstanced.cpp index b9bd53114..4fc4155a5 100644 --- a/src/game/MapInstanced.cpp +++ b/src/game/MapInstanced.cpp @@ -32,6 +32,17 @@ MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, 0) memset(&GridMapReference, 0, MAX_NUMBER_OF_GRIDS*MAX_NUMBER_OF_GRIDS*sizeof(uint16)); } +void MapInstanced::InitVisibilityDistance() +{ + if(m_InstancedMaps.empty()) + return; + //initialize visibility distances for all instance copies + for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) + { + (*i).second->InitVisibilityDistance(); + } +} + void MapInstanced::Update(const uint32& t) { // take care of loaded GridMaps (when unused, unload it!) diff --git a/src/game/MapInstanced.h b/src/game/MapInstanced.h index 67c57b98d..efb48b274 100644 --- a/src/game/MapInstanced.h +++ b/src/game/MapInstanced.h @@ -57,6 +57,7 @@ class MANGOS_DLL_DECL MapInstanced : public Map } InstancedMaps &GetInstancedMaps() { return m_InstancedMaps; } + virtual void InitVisibilityDistance(); private: diff --git a/src/game/MapManager.cpp b/src/game/MapManager.cpp index 57b9dd1dc..f98011e34 100644 --- a/src/game/MapManager.cpp +++ b/src/game/MapManager.cpp @@ -70,6 +70,12 @@ MapManager::Initialize() InitMaxInstanceId(); } +void MapManager::InitializeVisibilityDistanceInfo() +{ + for(MapMapType::iterator iter=i_maps.begin(); iter != i_maps.end(); ++iter) + (*iter).second->InitVisibilityDistance(); +} + // debugging code, should be deleted some day void MapManager::checkAndCorrectGridStatesArray() { diff --git a/src/game/MapManager.h b/src/game/MapManager.h index f88e62a36..0492f00f2 100644 --- a/src/game/MapManager.h +++ b/src/game/MapManager.h @@ -122,6 +122,7 @@ class MANGOS_DLL_DECL MapManager : public MaNGOS::Singleton > say_worker(this,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY),say_do); TypeContainerVisitor >, WorldTypeMapContainer > message(say_worker); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *GetMap()); + cell_lock->Visit(cell_lock, message, *GetMap(), *this, sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY)); } void WorldObject::MonsterYell(int32 textId, uint32 language, uint64 TargetGuid) @@ -1495,7 +1495,7 @@ void WorldObject::MonsterYell(int32 textId, uint32 language, uint64 TargetGuid) MaNGOS::PlayerDistWorker > say_worker(this,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL),say_do); TypeContainerVisitor >, WorldTypeMapContainer > message(say_worker); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *GetMap()); + cell_lock->Visit(cell_lock, message, *GetMap(), *this, sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL)); } void WorldObject::MonsterYellToZone(int32 textId, uint32 language, uint64 TargetGuid) @@ -1524,7 +1524,7 @@ void WorldObject::MonsterTextEmote(int32 textId, uint64 TargetGuid, bool IsBossE MaNGOS::PlayerDistWorker > say_worker(this,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),say_do); TypeContainerVisitor >, WorldTypeMapContainer > message(say_worker); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *GetMap()); + cell_lock->Visit(cell_lock, message, *GetMap(), *this, sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE)); } void WorldObject::MonsterWhisper(int32 textId, uint64 receiver, bool IsBossWhisper) @@ -1755,8 +1755,8 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, TypeContainerVisitor, WorldTypeMapContainer > world_obj_worker(worker); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_obj_worker, *GetMap()); - cell_lock->Visit(cell_lock, world_obj_worker, *GetMap()); + cell_lock->Visit(cell_lock, grid_obj_worker, *GetMap(), *this, distance2d); + cell_lock->Visit(cell_lock, world_obj_worker, *GetMap(), *this, distance2d); } // maybe can just place in primary position diff --git a/src/game/Object.h b/src/game/Object.h index 1bda374e3..adb23924c 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -32,10 +32,13 @@ #define CONTACT_DISTANCE 0.5f #define INTERACTION_DISTANCE 5.0f #define ATTACK_DISTANCE 5.0f -#define MAX_VISIBILITY_DISTANCE (5*SIZE_OF_GRID_CELL/2.0f) // max distance for visible object show, limited by active zone for player based at cell size (active zone = 5x5 cells) -#define DEFAULT_VISIBILITY_DISTANCE (SIZE_OF_GRID_CELL) // default visible distance +#define MAX_VISIBILITY_DISTANCE 333.0f // max distance for visible object show, limited in 333 yards +#define DEFAULT_VISIBILITY_DISTANCE 90.0f // default visible distance, 90 yards on continents +#define DEFAULT_VISIBILITY_INSTANCE 120.0f // default visible distance in instances, 120 yards +#define DEFAULT_VISIBILITY_BGARENAS 180.0f // default visible distance in BG/Arenas, 180 yards #define DEFAULT_WORLD_OBJECT_SIZE 0.388999998569489f // player size, also currently used (correctly?) for any non Unit world objects +#define MAX_STEALTH_DETECT_RANGE 45.0f enum TypeMask { diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp index ee8943781..1ceb156ce 100644 --- a/src/game/ObjectAccessor.cpp +++ b/src/game/ObjectAccessor.cpp @@ -254,7 +254,9 @@ ObjectAccessor::_buildChangeObjectForPlayer(WorldObject *obj, UpdateDataMapType WorldObjectChangeAccumulator notifier(*obj, update_players); TypeContainerVisitor player_notifier(notifier); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, player_notifier, *obj->GetMap()); + Map& map = *obj->GetMap(); + //we must build packets for all visible players + cell_lock->Visit(cell_lock, player_notifier, map, *obj, map.GetVisibilityDistance()); } Pet* diff --git a/src/game/Player.cpp b/src/game/Player.cpp index e25e606b2..a3afea53a 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -12137,34 +12137,36 @@ void Player::PrepareQuestMenu( uint64 guid ) } } -void Player::SendPreparedQuest( uint64 guid ) +void Player::SendPreparedQuest(uint64 guid) { QuestMenu& questMenu = PlayerTalkClass->GetQuestMenu(); - if( questMenu.Empty() ) + + if (questMenu.Empty()) return; - QuestMenuItem const& qmi0 = questMenu.GetItem( 0 ); + QuestMenuItem const& qmi0 = questMenu.GetItem(0); uint32 status = qmi0.m_qIcon; // single element case - if ( questMenu.MenuItemCount() == 1 ) + if (questMenu.MenuItemCount() == 1) { // Auto open -- maybe also should verify there is no greeting uint32 quest_id = qmi0.m_qId; Quest const* pQuest = objmgr.GetQuestTemplate(quest_id); - if ( pQuest ) + if (pQuest) { - if( status == DIALOG_STATUS_UNK2 && !GetQuestRewardStatus( quest_id ) ) - PlayerTalkClass->SendQuestGiverRequestItems( pQuest, guid, CanRewardQuest(pQuest, false), true ); - else if( status == DIALOG_STATUS_UNK2 ) - PlayerTalkClass->SendQuestGiverRequestItems( pQuest, guid, CanRewardQuest(pQuest, false), true ); - // Send completable on repeatable quest if player don't have quest - else if( pQuest->IsRepeatable() && !pQuest->IsDaily() ) - PlayerTalkClass->SendQuestGiverRequestItems( pQuest, guid, CanCompleteRepeatableQuest(pQuest), true ); + if (status == DIALOG_STATUS_UNK2 && !GetQuestRewardStatus(quest_id)) + PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, CanRewardQuest(pQuest, false), true); + else if (status == DIALOG_STATUS_UNK2) + PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, CanRewardQuest(pQuest, false), true); + // Send completable on repeatable and autoCompletable quest if player don't have quest + // TODO: verify if check for !pQuest->IsDaily() is really correct (possibly not) + else if (pQuest->IsAutoComplete() && pQuest->IsRepeatable() && !pQuest->IsDaily()) + PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, CanCompleteRepeatableQuest(pQuest), true); else - PlayerTalkClass->SendQuestGiverQuestDetails( pQuest, guid, true ); + PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, guid, true); } } // multiply entries @@ -12177,11 +12179,11 @@ void Player::SendPreparedQuest( uint64 guid ) // need pet case for some quests Creature *pCreature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this,guid); - if( pCreature ) + if (pCreature) { uint32 textid = pCreature->GetNpcTextId(); GossipText const* gossiptext = objmgr.GetGossipText(textid); - if( !gossiptext ) + if (!gossiptext) { qe._Delay = 0; //TEXTEMOTE_MESSAGE; //zyg: player emote qe._Emote = 0; //TEXTEMOTE_HELLO; //zyg: NPC emote @@ -12223,7 +12225,7 @@ void Player::SendPreparedQuest( uint64 guid ) } } } - PlayerTalkClass->SendQuestGiverQuestList( qe, title, guid ); + PlayerTalkClass->SendQuestGiverQuestList(qe, title, guid); } } @@ -16819,8 +16821,8 @@ void Player::HandleStealthedUnitsDetection() TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_unit_searcher, *GetMap()); - cell_lock->Visit(cell_lock, grid_unit_searcher, *GetMap()); + cell_lock->Visit(cell_lock, world_unit_searcher, *GetMap(), *this, MAX_PLAYER_STEALTH_DETECT_RANGE); + cell_lock->Visit(cell_lock, grid_unit_searcher, *GetMap(), *this, MAX_PLAYER_STEALTH_DETECT_RANGE); WorldObject const* viewPoint = GetViewPoint(); @@ -19631,7 +19633,7 @@ void Player::SetTitle(CharTitlesEntry const* title, bool lost) GetSession()->SendPacket(&data); } -void Player::ConvertRune(uint8 index, uint8 newType) +void Player::ConvertRune(uint8 index, RuneType newType) { SetCurrentRune(index, newType); @@ -19659,6 +19661,15 @@ void Player::AddRunePower(uint8 index) GetSession()->SendPacket(&data); } +static RuneType runeSlotTypes[MAX_RUNES] = { + /*0*/ RUNE_BLOOD, + /*1*/ RUNE_BLOOD, + /*2*/ RUNE_UNHOLY, + /*3*/ RUNE_UNHOLY, + /*4*/ RUNE_FROST, + /*5*/ RUNE_FROST +}; + void Player::InitRunes() { if(getClass() != CLASS_DEATH_KNIGHT) @@ -19670,8 +19681,8 @@ void Player::InitRunes() for(uint32 i = 0; i < MAX_RUNES; ++i) { - SetBaseRune(i, i / 2); // init base types - SetCurrentRune(i, i / 2); // init current types + SetBaseRune(i, runeSlotTypes[i]); // init base types + SetCurrentRune(i, runeSlotTypes[i]); // init current types SetRuneCooldown(i, 0); // reset cooldowns m_runes->SetRuneState(i); } @@ -19680,6 +19691,16 @@ void Player::InitRunes() SetFloatValue(PLAYER_RUNE_REGEN_1 + i, 0.1f); } + +bool Player::IsBaseRuneSlotsOnCooldown( RuneType runeType ) const +{ + for(uint32 i = 0; i < MAX_RUNES; ++i) + if (GetBaseRune(i) == runeType && GetRuneCooldown(i) == 0) + return false; + + return true; +} + void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore const& store, bool broadcast) { Loot loot; diff --git a/src/game/Player.h b/src/game/Player.h index d780e4691..049fb298a 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -2222,13 +2222,14 @@ class MANGOS_DLL_SPEC Player : public Unit DeclinedName const* GetDeclinedNames() const { return m_declinedname; } uint8 GetRunesState() const { return m_runes->runeState; } - uint8 GetBaseRune(uint8 index) const { return m_runes->runes[index].BaseRune; } - uint8 GetCurrentRune(uint8 index) const { return m_runes->runes[index].CurrentRune; } + RuneType GetBaseRune(uint8 index) const { return RuneType(m_runes->runes[index].BaseRune); } + RuneType GetCurrentRune(uint8 index) const { return RuneType(m_runes->runes[index].CurrentRune); } uint16 GetRuneCooldown(uint8 index) const { return m_runes->runes[index].Cooldown; } - void SetBaseRune(uint8 index, uint8 baseRune) { m_runes->runes[index].BaseRune = baseRune; } - void SetCurrentRune(uint8 index, uint8 currentRune) { m_runes->runes[index].CurrentRune = currentRune; } + bool IsBaseRuneSlotsOnCooldown(RuneType runeType) const; + void SetBaseRune(uint8 index, RuneType baseRune) { m_runes->runes[index].BaseRune = baseRune; } + void SetCurrentRune(uint8 index, RuneType currentRune) { m_runes->runes[index].CurrentRune = currentRune; } void SetRuneCooldown(uint8 index, uint16 cooldown) { m_runes->runes[index].Cooldown = cooldown; m_runes->SetRuneState(index, (cooldown == 0) ? true : false); } - void ConvertRune(uint8 index, uint8 newType); + void ConvertRune(uint8 index, RuneType newType); void ResyncRunes(uint8 count); void AddRunePower(uint8 index); void InitRunes(); diff --git a/src/game/PoolHandler.cpp b/src/game/PoolHandler.cpp index 6e6a71312..d1f2305bd 100644 --- a/src/game/PoolHandler.cpp +++ b/src/game/PoolHandler.cpp @@ -31,7 +31,8 @@ INSTANTIATE_SINGLETON_1(PoolHandler); template PoolGroup::PoolGroup() { - Spawned = 0; + m_SpawnedPoolAmount = 0; + m_LastDespawnedNode = 0; } // Method to add a gameobject/creature guid to the proper list depending on pool type and chance value @@ -107,12 +108,14 @@ void PoolGroup::DespawnObject(uint32 guid) if (!guid || EqualChanced[i].guid == guid) { if (guid) - CacheValue = EqualChanced[i].guid; + m_LastDespawnedNode = EqualChanced[i].guid; else Despawn1Object(EqualChanced[i].guid); EqualChanced[i].spawned = false; - Spawned--; + + if (m_SpawnedPoolAmount > 0) + --m_SpawnedPoolAmount; } } } @@ -182,36 +185,40 @@ void PoolGroup::SpawnObject(uint32 limit, bool cache) if (limit == 1) // This is the only case where explicit chance is used { uint32 roll = RollOne(); - if (cache && CacheValue != roll) - Despawn1Object(CacheValue); - CacheValue = Spawn1Object(roll); + if (cache && m_LastDespawnedNode != roll) + Despawn1Object(m_LastDespawnedNode); + + m_LastDespawnedNode = 0; + Spawn1Object(roll); } - else if (limit < EqualChanced.size() && Spawned < limit) + else if (limit < EqualChanced.size() && m_SpawnedPoolAmount < limit) { std::vector IndexList; for (size_t i = 0; i < EqualChanced.size(); ++i) if (!EqualChanced[i].spawned) IndexList.push_back(i); - while (Spawned < limit && IndexList.size() > 0) + while (m_SpawnedPoolAmount < limit && IndexList.size() > 0) { uint32 roll = urand(1, IndexList.size()) - 1; uint32 index = IndexList[roll]; - if (!cache || (cache && EqualChanced[index].guid != CacheValue)) + if (!cache || (cache && EqualChanced[index].guid != m_LastDespawnedNode)) { if (cache) - Despawn1Object(CacheValue); + Despawn1Object(m_LastDespawnedNode); + EqualChanced[index].spawned = Spawn1Object(EqualChanced[index].guid); } else EqualChanced[index].spawned = ReSpawn1Object(EqualChanced[index].guid); if (EqualChanced[index].spawned) - ++Spawned; // limited group use the Spawned variable to store the number of actualy spawned creatures + ++m_SpawnedPoolAmount; // limited group use the Spawned variable to store the number of actualy spawned creatures + std::vector::iterator itr = IndexList.begin()+roll; IndexList.erase(itr); } - CacheValue = 0; + m_LastDespawnedNode = 0; } else // Not enough objects in pool, so spawn all { @@ -330,7 +337,7 @@ bool PoolGroup::ReSpawn1Object(uint32 /*guid*/) PoolHandler::PoolHandler() { - isSystemInit = false; + m_IsPoolSystemStarted = false; } void PoolHandler::LoadFromDB() @@ -624,7 +631,7 @@ void PoolHandler::Initialize() } sLog.outBasic("Pool handling system initialized, %u pools spawned.", count); - isSystemInit = true; + m_IsPoolSystemStarted = true; } // Call to spawn a pool, if cache if true the method will spawn only if cached entry is different diff --git a/src/game/PoolHandler.h b/src/game/PoolHandler.h index 8b6c82d11..652d8e2cf 100644 --- a/src/game/PoolHandler.h +++ b/src/game/PoolHandler.h @@ -56,10 +56,10 @@ class PoolGroup void RemoveOneRelation(uint16 child_pool_id); private: typedef std::vector PoolObjectList; - uint32 CacheValue; // Store the guid of the removed creature/gameobject during a pool update PoolObjectList ExplicitlyChanced; PoolObjectList EqualChanced; - uint32 Spawned; // Used to know the number of spawned objects + uint32 m_LastDespawnedNode; // Store the guid of the removed creature/gameobject during a pool update + uint32 m_SpawnedPoolAmount; // Used to know the number of spawned objects }; class Pool // for Pool of Pool case @@ -81,7 +81,7 @@ class PoolHandler void Initialize(); protected: - bool isSystemInit; + bool m_IsPoolSystemStarted; uint16 max_pool_id; typedef std::vector PoolTemplateDataMap; typedef std::vector > PoolGroupCreatureMap; diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 13590039c..9a6901a19 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -2433,9 +2433,12 @@ enum SummonType SUMMON_TYPE_UNKNOWN5 = 409, SUMMON_TYPE_UNKNOWN2 = 427, SUMMON_TYPE_POSESSED2 = 428, + SUMMON_TYPE_QUEST_CRITTER = 487, + SUMMON_TYPE_QUEST_WILD = 587, SUMMON_TYPE_INFERNO = 711, SUMMON_TYPE_GUARDIAN2 = 713, SUMMON_TYPE_GUARDIAN3 = 1161, + SUMMON_TYPE_CREATURE = 1302, SUMMON_TYPE_ELEMENTAL = 1561, SUMMON_TYPE_FORCE_OF_NATURE = 1562 }; diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 9335636c6..9bffe0d49 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -476,12 +476,12 @@ WorldObject* Spell::FindCorpseUsing() TypeContainerVisitor, GridTypeMapContainer > grid_searcher(searcher); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_searcher, *m_caster->GetMap()); + cell_lock->Visit(cell_lock, grid_searcher, *m_caster->GetMap(), *m_caster, max_range); if (!result) { TypeContainerVisitor, WorldTypeMapContainer > world_searcher(searcher); - cell_lock->Visit(cell_lock, world_searcher, *m_caster->GetMap()); + cell_lock->Visit(cell_lock, world_searcher, *m_caster->GetMap(), *m_caster, max_range); } return result; @@ -970,7 +970,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) // Do healing and triggers if (m_healing) { - bool crit = caster->isSpellCrit(NULL, m_spellInfo, m_spellSchoolMask); + bool crit = caster->isSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask); uint32 addhealth = m_healing; if (crit) { @@ -1356,8 +1356,8 @@ void Spell::SetTargetMap(uint32 effIndex,uint32 targetMode,UnitList& TagUnitMap) TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_unit_searcher, *m_caster->GetMap()); - cell_lock->Visit(cell_lock, grid_unit_searcher, *m_caster->GetMap()); + cell_lock->Visit(cell_lock, world_unit_searcher, *m_caster->GetMap(), *m_caster, max_range); + cell_lock->Visit(cell_lock, grid_unit_searcher, *m_caster->GetMap(), *m_caster, max_range); } if(tempUnitMap.empty()) @@ -1426,8 +1426,8 @@ void Spell::SetTargetMap(uint32 effIndex,uint32 targetMode,UnitList& TagUnitMap) TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_unit_searcher, *m_caster->GetMap()); - cell_lock->Visit(cell_lock, grid_unit_searcher, *m_caster->GetMap()); + cell_lock->Visit(cell_lock, world_unit_searcher, *m_caster->GetMap(), *m_caster, max_range); + cell_lock->Visit(cell_lock, grid_unit_searcher, *m_caster->GetMap(), *m_caster, max_range); } if(tempUnitMap.empty()) @@ -1522,8 +1522,8 @@ void Spell::SetTargetMap(uint32 effIndex,uint32 targetMode,UnitList& TagUnitMap) TypeContainerVisitor, GridTypeMapContainer> grid_unit_searcher(searcher); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_unit_searcher, *m_caster->GetMap()); - cell_lock->Visit(cell_lock, grid_unit_searcher, *m_caster->GetMap()); + cell_lock->Visit(cell_lock, world_unit_searcher, *m_caster->GetMap(), *pUnitTarget, max_range); + cell_lock->Visit(cell_lock, grid_unit_searcher, *m_caster->GetMap(), *pUnitTarget, max_range); } if (tempUnitMap.empty()) break; @@ -3556,7 +3556,7 @@ SpellCastResult Spell::CheckRuneCost(uint32 runeCostID) for(uint32 i = 0; i < MAX_RUNES; ++i) { - uint8 rune = plr->GetCurrentRune(i); + RuneType rune = plr->GetCurrentRune(i); if((plr->GetRuneCooldown(i) == 0) && (runeCost[rune] > 0)) runeCost[rune]--; } @@ -3599,7 +3599,7 @@ void Spell::TakeRunePower() for(uint32 i = 0; i < MAX_RUNES; ++i) { - uint8 rune = plr->GetCurrentRune(i); + RuneType rune = plr->GetCurrentRune(i); if((plr->GetRuneCooldown(i) == 0) && (runeCost[rune] > 0)) { plr->SetRuneCooldown(i, RUNE_COOLDOWN); // 5*2=10 sec @@ -3613,7 +3613,7 @@ void Spell::TakeRunePower() { for(uint32 i = 0; i < MAX_RUNES; ++i) { - uint8 rune = plr->GetCurrentRune(i); + RuneType rune = plr->GetCurrentRune(i); if((plr->GetRuneCooldown(i) == 0) && (rune == RUNE_DEATH)) { plr->SetRuneCooldown(i, RUNE_COOLDOWN); // 5*2=10 sec @@ -4089,7 +4089,7 @@ SpellCastResult Spell::CheckCast(bool strict) TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *m_caster->GetMap()); + cell_lock->Visit(cell_lock, object_checker, *m_caster->GetMap(), *m_caster, range); if (p_GameObject) { @@ -4128,7 +4128,7 @@ SpellCastResult Spell::CheckCast(bool strict) TypeContainerVisitor, GridTypeMapContainer > grid_creature_searcher(searcher); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *m_caster->GetMap()); + cell_lock->Visit(cell_lock, grid_creature_searcher, *m_caster->GetMap(), *m_caster, range); if(p_Creature ) { @@ -5189,7 +5189,8 @@ SpellCastResult Spell::CheckItems() TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *m_caster->GetMap()); + Map& map = *m_caster->GetMap(); + cell_lock->Visit(cell_lock, object_checker, map, *m_caster, map.GetVisibilityDistance()); if(!ok) return SPELL_FAILED_REQUIRES_SPELL_FOCUS; diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 9b7515201..53cd09647 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -460,6 +460,13 @@ m_isRemovedOnShapeLost(true), m_in_use(0), m_deleted(false) m_spellProto->Stances && !(m_spellProto->AttributesEx2 & SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT) && !(m_spellProto->Attributes & SPELL_ATTR_NOT_SHAPESHIFT)); + + if (caster && m_spellProto->Id == 22959) // Improved Scorch + { + // Glyph of Improved Scorch + if (Aura* glyph = caster->GetDummyAura(56371)) + m_stackAmount = glyph->GetModifier()->m_amount; + } } Aura::~Aura() @@ -754,8 +761,8 @@ void AreaAura::Update(uint32 diff) TypeContainerVisitor, WorldTypeMapContainer > world_unit_searcher(searcher); TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_unit_searcher, *caster->GetMap()); - cell_lock->Visit(cell_lock, grid_unit_searcher, *caster->GetMap()); + cell_lock->Visit(cell_lock, world_unit_searcher, *caster->GetMap(), *caster, m_radius); + cell_lock->Visit(cell_lock, grid_unit_searcher, *caster->GetMap(), *caster, m_radius); break; } case AREA_AURA_ENEMY: @@ -770,8 +777,8 @@ void AreaAura::Update(uint32 diff) TypeContainerVisitor, WorldTypeMapContainer > world_unit_searcher(searcher); TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_unit_searcher, *caster->GetMap()); - cell_lock->Visit(cell_lock, grid_unit_searcher, *caster->GetMap()); + cell_lock->Visit(cell_lock, world_unit_searcher, *caster->GetMap(), *caster, m_radius); + cell_lock->Visit(cell_lock, grid_unit_searcher, *caster->GetMap(), *caster, m_radius); break; } case AREA_AURA_OWNER: @@ -5001,7 +5008,8 @@ void Aura::HandleAuraModIncreaseHealth(bool apply, bool Real) case 12976: // Warrior Last Stand triggered spell case 28726: // Nightmare Seed ( Nightmare Seed ) case 34511: // Valor (Bulwark of Kings, Bulwark of the Ancient Kings) - case 44055: // Tremendous Fortitude (Battlemaster's Alacrity) + // FIXME: add case 67596: in 3.2.x + case 44055: case 55915: case 55917: // Tremendous Fortitude (Battlemaster's Alacrity) case 50322: // Survival Instincts case 54443: // Demonic Empowerment (Voidwalker) { @@ -6141,6 +6149,15 @@ void Aura::HandleSchoolAbsorb(bool apply, bool Real) //+30% from +spell bonus DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.30f; break; + case SPELLFAMILY_PALADIN: + // Sacred Shield + // (check not strictly needed, only Sacred Shield has SPELL_AURA_SCHOOL_ABSORB in SPELLFAMILY_PALADIN at this time) + if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0008000000000000)) + { + // +75% from spell power + DoneActualBenefit = caster->SpellBaseHealingBonus(GetSpellSchoolMask(m_spellProto)) * 0.75f; + } + break; case SPELLFAMILY_DRUID: // Savage Defense (amount store original percent of attack power applied) if (m_spellProto->SpellIconID == 50) // only spell with this aura fit @@ -6153,6 +6170,26 @@ void Aura::HandleSchoolAbsorb(bool apply, bool Real) DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellProto()); m_modifier.m_amount += (int32)DoneActualBenefit; + + // now that the correct amount is computed, apply caster aura, if any + switch(m_spellProto->SpellFamilyName) + { + case SPELLFAMILY_PRIEST: + // Power Word: Shield + if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000001)) + { + // Glyph of Power Word: Shield + if(Aura* glyph = caster->GetAura(55672,0)) + { + // instant heal glyph m_amount% of the absorbed amount + int32 heal = (glyph->GetModifier()->m_amount * m_modifier.m_amount)/100; + caster->CastCustomSpell(m_target, 56160, &heal, NULL, NULL, true, 0, this); + } + } + break; + default: + break; + } } } else @@ -7025,8 +7062,8 @@ void Aura::PeriodicDummyTick() CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_object_checker, *caster->GetMap()); - cell_lock->Visit(cell_lock, world_object_checker, *caster->GetMap()); + cell_lock->Visit(cell_lock, grid_object_checker, *caster->GetMap(), *caster, radius); + cell_lock->Visit(cell_lock, world_object_checker, *caster->GetMap(), *caster, radius); } if(targets.empty()) @@ -7175,7 +7212,7 @@ void Aura::HandleManaShield(bool apply, bool Real) switch(m_spellProto->SpellFamilyName) { case SPELLFAMILY_MAGE: - if(m_spellProto->SpellFamilyFlags & UI64LIT(0x8000)) + if(m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000008000)) { // Mana Shield // +50% from +spd bonus @@ -7256,13 +7293,13 @@ void Aura::HandleAuraConvertRune(bool apply, bool Real) { if(!plr->GetRuneCooldown(i)) { - plr->ConvertRune(i, GetSpellProto()->EffectMiscValueB[m_effIndex]); + plr->ConvertRune(i, RuneType(GetSpellProto()->EffectMiscValueB[m_effIndex])); break; } } else { - if(plr->GetCurrentRune(i) == GetSpellProto()->EffectMiscValueB[m_effIndex]) + if(plr->GetCurrentRune(i) == RuneType(GetSpellProto()->EffectMiscValueB[m_effIndex])) { plr->ConvertRune(i, plr->GetBaseRune(i)); break; diff --git a/src/game/SpellAuras.h b/src/game/SpellAuras.h index 98fe1111d..053d24547 100644 --- a/src/game/SpellAuras.h +++ b/src/game/SpellAuras.h @@ -262,7 +262,7 @@ class MANGOS_DLL_SPEC Aura m_procCharges = charges; SendAuraUpdate(false); } - bool DropAuraCharge() // return true if last charge dropped + bool DropAuraCharge() // return true if last charge dropped { if (m_procCharges == 0) return false; diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index bb2a943ee..f4324ac46 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -669,6 +669,12 @@ void Spell::EffectSchoolDMG(uint32 effect_idx) { damage+=int32(m_caster->GetShieldBlockValue()); } + // Judgement + else if (m_spellInfo->Id == 54158) + { + // [1 + 0.25 * SPH + 0.16 * AP] + damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.16f); + } break; } } @@ -1636,6 +1642,25 @@ void Spell::EffectDummy(uint32 i) ((Player*)m_caster)->SendAttackSwingCancelAttack(); return; } + // Last Stand + case 53478: + { + if (!unitTarget) + return; + int32 healthModSpellBasePoints0 = int32(unitTarget->GetMaxHealth() * 0.3); + unitTarget->CastCustomSpell(unitTarget, 53479, &healthModSpellBasePoints0, NULL, NULL, true, NULL); + return; + } + // Master's Call + case 53271: + { + Pet* pet = m_caster->GetPet(); + if (!pet || !unitTarget) + return; + + pet->CastSpell(unitTarget, m_spellInfo->CalculateSimpleValue(i), true); + return; + } } break; case SPELLFAMILY_PALADIN: @@ -3297,6 +3322,8 @@ void Spell::EffectSummonType(uint32 i) EffectSummonGuardian(i); break; case SUMMON_TYPE_WILD: + case SUMMON_TYPE_QUEST_WILD: + case SUMMON_TYPE_CREATURE: EffectSummonWild(i); break; case SUMMON_TYPE_DEMON: @@ -3310,6 +3337,7 @@ void Spell::EffectSummonType(uint32 i) case SUMMON_TYPE_CRITTER: case SUMMON_TYPE_CRITTER2: case SUMMON_TYPE_CRITTER3: + case SUMMON_TYPE_QUEST_CRITTER: EffectSummonCritter(i); break; case SUMMON_TYPE_TOTEM_SLOT1: @@ -5374,6 +5402,16 @@ void Spell::EffectScriptEffect(uint32 effIndex) } return; } + // Master's Call + case 53271: + { + if (!unitTarget) + return; + + // script effect have in value, but this outdated removed part + unitTarget->CastSpell(unitTarget, 62305, true); + return; + } default: break; } @@ -5400,13 +5438,12 @@ void Spell::EffectScriptEffect(uint32 effIndex) sLog.outError("Unsupported Judgement (seal trigger) spell (Id: %u) in Spell::EffectScriptEffect",m_spellInfo->Id); return; } - // all seals have aura dummy in 2 effect + // offensive seals have aura dummy in 2 effect Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr) { - SpellEntry const *spellInfo = (*itr)->GetSpellProto(); - // search seal (all seals have judgement's aura dummy spell id in 2 effect - if ((*itr)->GetEffIndex() != 2 || !spellInfo || !IsSealSpell(spellInfo)) + // search seal (offensive seals have judgement's aura dummy spell id in 2 effect + if ((*itr)->GetEffIndex() != 2 || !IsSealSpell((*itr)->GetSpellProto())) continue; spellId2 = (*itr)->GetModifier()->m_amount; SpellEntry const *judge = sSpellStore.LookupEntry(spellId2); @@ -5414,6 +5451,18 @@ void Spell::EffectScriptEffect(uint32 effIndex) continue; break; } + // if there were no offensive seals than there is seal with proc trigger aura + if (!spellId2) + { + Unit::AuraList const& procTriggerAuras = m_caster->GetAurasByType(SPELL_AURA_PROC_TRIGGER_SPELL); + for(Unit::AuraList::const_iterator itr = procTriggerAuras.begin(); itr != procTriggerAuras.end(); ++itr) + { + if ((*itr)->GetEffIndex() != 0 || !IsSealSpell((*itr)->GetSpellProto())) + continue; + spellId2 = 54158; + break; + } + } if (spellId1) m_caster->CastSpell(unitTarget, spellId1, true); if (spellId2) @@ -6830,7 +6879,7 @@ void Spell::EffectActivateRune(uint32 eff_idx) for(uint32 j = 0; j < MAX_RUNES; ++j) { - if(plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == m_spellInfo->EffectMiscValue[eff_idx]) + if(plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == RuneType(m_spellInfo->EffectMiscValue[eff_idx])) { plr->SetRuneCooldown(j, 0); } diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index cd67d6de1..7bc2f8613 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -1501,6 +1501,10 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons // Savage Roar and Savage Roar (triggered) if (spellInfo_1->SpellIconID == 2865 && spellInfo_2->SpellIconID == 2865) return false; + + // Frenzied Regeneration and Savage Defense + if( spellInfo_1->Id == 22842 && spellInfo_2->Id == 62606 || spellInfo_2->Id == 22842 && spellInfo_1->Id == 62606 ) + return false; } // Leader of the Pack and Scroll of Stamina (multi-family check) diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h index 86388e2af..45bc53d41 100644 --- a/src/game/SpellMgr.h +++ b/src/game/SpellMgr.h @@ -156,7 +156,9 @@ inline bool IsSealSpell(SpellEntry const *spellInfo) { //Collection of all the seal family flags. No other paladin spell has any of those. return spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && - ( spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_PALADIN_SEALS ); + ( spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_PALADIN_SEALS ) && + // avoid counting target triggered effect as seal for avoid remove it or seal by it. + spellInfo->EffectImplicitTargetA[0] == TARGET_SELF; } inline bool IsElementalShield(SpellEntry const *spellInfo) diff --git a/src/game/TotemAI.cpp b/src/game/TotemAI.cpp index b826bef03..867aca762 100644 --- a/src/game/TotemAI.cpp +++ b/src/game/TotemAI.cpp @@ -91,8 +91,8 @@ TotemAI::UpdateAI(const uint32 /*diff*/) TypeContainerVisitor, WorldTypeMapContainer > world_object_checker(checker); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_object_checker, *m_creature->GetMap()); - cell_lock->Visit(cell_lock, world_object_checker, *m_creature->GetMap()); + cell_lock->Visit(cell_lock, grid_object_checker, *m_creature->GetMap(), *m_creature, max_range); + cell_lock->Visit(cell_lock, world_object_checker, *m_creature->GetMap(), *m_creature, max_range); } // If have target diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index c438a479b..d23cb7773 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -1862,6 +1862,8 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe // Reduce shield amount mod->m_amount-=currentAbsorb; + if((*i)->DropAuraCharge()) + mod->m_amount = 0; // Need remove it later if (mod->m_amount<=0) existExpired = true; @@ -3436,7 +3438,8 @@ bool Unit::AddAura(Aura *Aur) // Aura can stack on self -> Stack it; if(aurSpellInfo->StackAmount) { - i2->second->modStackAmount(1); + // can be created with >1 stack by some spell mods + i2->second->modStackAmount(Aur->GetStackAmount()); delete Aur; return false; } @@ -5134,6 +5137,16 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu CastSpell(this, 28682, true, castItem, triggeredByAura); return (procEx & PROC_EX_CRITICAL_HIT); // charge update only at crit hits, no hidden cooldowns } + // Glyph of Ice Block + case 56372: + { + if (GetTypeId() != TYPEID_PLAYER) + return false; + + // not 100% safe with client version switches but for 3.1.3 no spells with cooldown that can have mage player except Frost Nova. + ((Player*)this)->RemoveSpellCategoryCooldown(35, true); + return true; + } } break; } @@ -6121,8 +6134,16 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu // Earth Shield if (dummySpell->SpellFamilyFlags & UI64LIT(0x0000040000000000)) { - basepoints0 = triggerAmount; target = this; + basepoints0 = triggerAmount; + + // Glyph of Earth Shield + if (Aura* aur = GetDummyAura(63279)) + { + int32 aur_mod = aur->GetModifier()->m_amount; + basepoints0 = int32(basepoints0 * (aur_mod + 100.0f) / 100.0f); + } + triggered_spell_id = 379; break; } @@ -6983,6 +7004,12 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB break; } } + // Blade Barrier + if (auraSpellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && auraSpellInfo->SpellIconID == 85) + { + if (this->GetTypeId() != TYPEID_PLAYER || !((Player*)this)->IsBaseRuneSlotsOnCooldown(RUNE_BLOOD)) + return false; + } // Custom basepoints/target for exist spell // dummy basepoints or other customs @@ -8218,7 +8245,17 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3 if (spellProto->SpellIconID == 186) { if (pVictim->isFrozen()) - DoneTotalMod *= 3.0f; + { + float multiplier = 3.0f; + + // if target have higher level + if (pVictim->getLevel() > getLevel()) + // Glyph of Ice Lance + if (Aura* glyph = GetDummyAura(56377)) + multiplier = glyph->GetModifier()->m_amount; + + DoneTotalMod *= multiplier; + } } // Torment the weak affected (Arcane Barrage, Arcane Blast, Frostfire Bolt, Arcane Missiles, Fireball) if ((spellProto->SpellFamilyFlags & UI64LIT(0x0000900020200021)) && @@ -8475,7 +8512,8 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM crit_chance -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL); } - // scripted (increase crit chance ... against ... target by x% + // scripted (increase crit chance ... against ... target by x%) + // scripted (Increases the critical effect chance of your .... by x% on targets ...) AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) { @@ -8486,21 +8524,15 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM case 849: if (pVictim->isFrozen()) crit_chance+= 17.0f; break; //Shatter Rank 1 case 910: if (pVictim->isFrozen()) crit_chance+= 34.0f; break; //Shatter Rank 2 case 911: if (pVictim->isFrozen()) crit_chance+= 50.0f; break; //Shatter Rank 3 - case 7917: // Glyph of Shadowburn + case 7917: // Glyph of Shadowburn if (pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) crit_chance+=(*i)->GetModifier()->m_amount; break; - case 7997: // Renewed Hope + case 7997: // Renewed Hope case 7998: if (pVictim->HasAura(6788)) crit_chance+=(*i)->GetModifier()->m_amount; break; - case 21: // Test of Faith - case 6935: - case 6918: - if (pVictim->GetHealth() < pVictim->GetMaxHealth()/2) - crit_chance+=(*i)->GetModifier()->m_amount; - break; default: break; } @@ -8508,23 +8540,40 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM // Custom crit by class switch(spellProto->SpellFamilyName) { + case SPELLFAMILY_PRIEST: + // Flash Heal + if (spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000800)) + { + if (pVictim->GetHealth() > pVictim->GetMaxHealth()/2) + break; + AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_DUMMY); + for(AuraList::const_iterator i = mDummyAuras.begin(); i!= mDummyAuras.end(); ++i) + { + // Improved Flash Heal + if ((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST && + (*i)->GetSpellProto()->SpellIconID == 2542) + { + crit_chance+=(*i)->GetModifier()->m_amount; + break; + } + } + } + break; case SPELLFAMILY_PALADIN: // Sacred Shield if (spellProto->SpellFamilyFlags & UI64LIT(0x0000000040000000)) { Aura *aura = pVictim->GetDummyAura(58597); if (aura && aura->GetCasterGUID() == GetGUID()) - crit_chance+=aura->GetModifier()->m_amount; - break; + crit_chance+=aura->GetModifier()->m_amount; } // Exorcism else if (spellProto->Category == 19) { if (pVictim->GetCreatureTypeMask() & CREATURE_TYPEMASK_DEMON_OR_UNDEAD) return true; - break; } - break; + break; case SPELLFAMILY_SHAMAN: // Lava Burst if (spellProto->SpellFamilyFlags & UI64LIT(0x0000100000000000)) @@ -8536,9 +8585,8 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM pVictim->RemoveAurasByCasterSpell(flameShock->GetId(), GetGUID()); return true; } - break; } - break; + break; } } break; @@ -9417,7 +9465,7 @@ int32 Unit::ModifyPower(Powers power, int32 dVal) bool Unit::isVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, bool detect, bool inVisibleList, bool is3dDistance) const { - if(!u) + if(!u || !IsInMap(u)) return false; // Always can see self @@ -9440,6 +9488,7 @@ bool Unit::isVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, boo if(m_Visibility==VISIBILITY_RESPAWN) return false; + Map& _map = *u->GetMap(); // Grid dead/alive checks if( u->GetTypeId()==TYPEID_PLAYER) { @@ -9483,26 +9532,26 @@ bool Unit::isVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, boo if(u->GetTypeId()==TYPEID_PLAYER) { // Players far than max visible distance for player or not in our map are not visible too - if (!at_same_transport && !IsWithinDistInMap(viewPoint,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) + if (!at_same_transport && !IsWithinDistInMap(viewPoint, _map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) return false; } else { // Units far than max visible distance for creature or not in our map are not visible too - if (!IsWithinDistInMap(viewPoint,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) + if (!IsWithinDistInMap(viewPoint, _map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) return false; } } else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed { // Pet/charmed far than max visible distance for player or not in our map are not visible too - if (!IsWithinDistInMap(viewPoint,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) + if (!IsWithinDistInMap(viewPoint, _map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) return false; } else // distance for show creature { // Units far than max visible distance for creature or not in our map are not visible too - if (!IsWithinDistInMap(viewPoint,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) + if (!IsWithinDistInMap(viewPoint, _map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) return false; } @@ -11690,8 +11739,8 @@ Unit* Unit::SelectNearbyTarget(Unit* except /*= NULL*/) const TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_unit_searcher, *GetMap()); - cell_lock->Visit(cell_lock, grid_unit_searcher, *GetMap()); + cell_lock->Visit(cell_lock, world_unit_searcher, *GetMap(), *this, ATTACK_DISTANCE); + cell_lock->Visit(cell_lock, grid_unit_searcher, *GetMap(), *this, ATTACK_DISTANCE); } // remove current target diff --git a/src/game/World.cpp b/src/game/World.cpp index 22570df38..4ebd61694 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -69,9 +69,11 @@ volatile bool World::m_stopEvent = false; uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE; volatile uint32 World::m_worldLoopCounter = 0; -float World::m_MaxVisibleDistanceForCreature = DEFAULT_VISIBILITY_DISTANCE; -float World::m_MaxVisibleDistanceForPlayer = DEFAULT_VISIBILITY_DISTANCE; +float World::m_MaxVisibleDistanceOnContinents = DEFAULT_VISIBILITY_DISTANCE; +float World::m_MaxVisibleDistanceInInctances = DEFAULT_VISIBILITY_INSTANCE; +float World::m_MaxVisibleDistanceInBGArenas = DEFAULT_VISIBILITY_BGARENAS; float World::m_MaxVisibleDistanceForObject = DEFAULT_VISIBILITY_DISTANCE; + float World::m_MaxVisibleDistanceInFlight = DEFAULT_VISIBILITY_DISTANCE; float World::m_VisibleUnitGreyDistance = 0; float World::m_VisibleObjectGreyDistance = 0; @@ -1007,28 +1009,45 @@ void World::LoadConfigSettings(bool reload) m_VisibleObjectGreyDistance = MAX_VISIBILITY_DISTANCE; } - m_MaxVisibleDistanceForCreature = sConfig.GetFloatDefault("Visibility.Distance.Creature", DEFAULT_VISIBILITY_DISTANCE); - if(m_MaxVisibleDistanceForCreature < 45*sWorld.getRate(RATE_CREATURE_AGGRO)) + //visibility on continents + m_MaxVisibleDistanceOnContinents = sConfig.GetFloatDefault("Visibility.Distance.Continents", DEFAULT_VISIBILITY_DISTANCE); + if(m_MaxVisibleDistanceOnContinents < 45*sWorld.getRate(RATE_CREATURE_AGGRO)) { - sLog.outError("Visibility.Distance.Creature can't be less max aggro radius %f",45*sWorld.getRate(RATE_CREATURE_AGGRO)); - m_MaxVisibleDistanceForCreature = 45*sWorld.getRate(RATE_CREATURE_AGGRO); + sLog.outError("Visibility.Distance.Continents can't be less max aggro radius %f", 45*sWorld.getRate(RATE_CREATURE_AGGRO)); + m_MaxVisibleDistanceOnContinents = 45*sWorld.getRate(RATE_CREATURE_AGGRO); } - else if(m_MaxVisibleDistanceForCreature + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) + else if(m_MaxVisibleDistanceOnContinents + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) { - sLog.outError("Visibility. Distance .Creature can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance); - m_MaxVisibleDistanceForCreature = MAX_VISIBILITY_DISTANCE-m_VisibleUnitGreyDistance; + sLog.outError("Visibility.Distance.Continents can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance); + m_MaxVisibleDistanceOnContinents = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance; } - m_MaxVisibleDistanceForPlayer = sConfig.GetFloatDefault("Visibility.Distance.Player", DEFAULT_VISIBILITY_DISTANCE); - if(m_MaxVisibleDistanceForPlayer < 45*sWorld.getRate(RATE_CREATURE_AGGRO)) + + //visibility in instances + m_MaxVisibleDistanceInInctances = sConfig.GetFloatDefault("Visibility.Distance.Instances", DEFAULT_VISIBILITY_INSTANCE); + if(m_MaxVisibleDistanceInInctances < 45*sWorld.getRate(RATE_CREATURE_AGGRO)) { - sLog.outError("Visibility.Distance.Player can't be less max aggro radius %f",45*sWorld.getRate(RATE_CREATURE_AGGRO)); - m_MaxVisibleDistanceForPlayer = 45*sWorld.getRate(RATE_CREATURE_AGGRO); + sLog.outError("Visibility.Distance.Instances can't be less max aggro radius %f",45*sWorld.getRate(RATE_CREATURE_AGGRO)); + m_MaxVisibleDistanceInInctances = 45*sWorld.getRate(RATE_CREATURE_AGGRO); } - else if(m_MaxVisibleDistanceForPlayer + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) + else if(m_MaxVisibleDistanceInInctances + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) { - sLog.outError("Visibility.Distance.Player can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance); - m_MaxVisibleDistanceForPlayer = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance; + sLog.outError("Visibility.Distance.Instances can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance); + m_MaxVisibleDistanceInInctances = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance; } + + //visibility in BG/Arenas + m_MaxVisibleDistanceInBGArenas = sConfig.GetFloatDefault("Visibility.Distance.BGArenas", DEFAULT_VISIBILITY_BGARENAS); + if(m_MaxVisibleDistanceInBGArenas < 45*sWorld.getRate(RATE_CREATURE_AGGRO)) + { + sLog.outError("Visibility.Distance.BGArenas can't be less max aggro radius %f",45*sWorld.getRate(RATE_CREATURE_AGGRO)); + m_MaxVisibleDistanceInBGArenas = 45*sWorld.getRate(RATE_CREATURE_AGGRO); + } + else if(m_MaxVisibleDistanceInBGArenas + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) + { + sLog.outError("Visibility.Distance.BGArenas can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance); + m_MaxVisibleDistanceInBGArenas = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance; + } + m_MaxVisibleDistanceForObject = sConfig.GetFloatDefault("Visibility.Distance.Object", DEFAULT_VISIBILITY_DISTANCE); if(m_MaxVisibleDistanceForObject < INTERACTION_DISTANCE) { diff --git a/src/game/World.h b/src/game/World.h index f8d5b908a..73883c4c3 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -494,12 +494,14 @@ class World bool IsScriptScheduled() const { return m_scheduledScripts > 0; } // for max speed access - static float GetMaxVisibleDistanceForCreature() { return m_MaxVisibleDistanceForCreature; } - static float GetMaxVisibleDistanceForPlayer() { return m_MaxVisibleDistanceForPlayer; } - static float GetMaxVisibleDistanceForObject() { return m_MaxVisibleDistanceForObject; } - static float GetMaxVisibleDistanceInFlight() { return m_MaxVisibleDistanceInFlight; } - static float GetVisibleUnitGreyDistance() { return m_VisibleUnitGreyDistance; } - static float GetVisibleObjectGreyDistance() { return m_VisibleObjectGreyDistance; } + static float GetMaxVisibleDistanceOnContinents() { return m_MaxVisibleDistanceOnContinents; } + static float GetMaxVisibleDistanceInInstances() { return m_MaxVisibleDistanceInInctances; } + static float GetMaxVisibleDistanceInBGArenas() { return m_MaxVisibleDistanceInBGArenas; } + static float GetMaxVisibleDistanceForObject() { return m_MaxVisibleDistanceForObject; } + + static float GetMaxVisibleDistanceInFlight() { return m_MaxVisibleDistanceInFlight; } + static float GetVisibleUnitGreyDistance() { return m_VisibleUnitGreyDistance; } + static float GetVisibleObjectGreyDistance() { return m_VisibleObjectGreyDistance; } void ProcessCliCommands(); void QueueCliCommand( CliCommandHolder::Print* zprintf, char const* input ) { cliCmdQueue.add(new CliCommandHolder(input, zprintf)); } @@ -560,9 +562,11 @@ class World std::string m_dataPath; // for max speed access - static float m_MaxVisibleDistanceForCreature; - static float m_MaxVisibleDistanceForPlayer; + static float m_MaxVisibleDistanceOnContinents; + static float m_MaxVisibleDistanceInInctances; + static float m_MaxVisibleDistanceInBGArenas; static float m_MaxVisibleDistanceForObject; + static float m_MaxVisibleDistanceInFlight; static float m_VisibleUnitGreyDistance; static float m_VisibleObjectGreyDistance; diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.in index a0dcb2195..e559642f9 100644 --- a/src/mangosd/mangosd.conf.dist.in +++ b/src/mangosd/mangosd.conf.dist.in @@ -962,12 +962,12 @@ GM.AllowAchievementGain = 1 # 1 (raid members 100% auto detect invisible player from same raid) # 2 (players from same team can 100% auto detect invisible player) # -# Visibility.Distance.Creature -# Visibility.Distance.Player -# Visibility distance for different in game object +# Visibility.Distance.Continents +# Visibility.Distance.Instances +# Visibility.Distance.BGArenas +# Visibility distance for different ingame object in different maps. +# Visibility on continents on offy ~90 yards. In BG/Arenas ~180. For instances default ~120. # Max limited by active player zone: ~ 333 -# Min limit dependent from objects -# Default: 132 (cell size) # Min limit is max aggro radius (45) * Rate.Creature.Aggro # # Visibility.Distance.Object @@ -993,8 +993,9 @@ GM.AllowAchievementGain = 1 ################################################################################################################### Visibility.GroupMode = 0 -Visibility.Distance.Creature = 100 -Visibility.Distance.Player = 100 +Visibility.Distance.Continents = 90 +Visibility.Distance.Instances = 120 +Visibility.Distance.BGArenas = 180 Visibility.Distance.Object = 100 Visibility.Distance.InFlight = 100 Visibility.Distance.Grey.Unit = 1 diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 6e4f79c60..58fc7f3ed 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "8502" + #define REVISION_NR "8526" #endif // __REVISION_NR_H__ diff --git a/src/shared/revision_sql.h b/src/shared/revision_sql.h index 0bbec6660..686c79b73 100644 --- a/src/shared/revision_sql.h +++ b/src/shared/revision_sql.h @@ -1,6 +1,6 @@ #ifndef __REVISION_SQL_H__ #define __REVISION_SQL_H__ - #define REVISION_DB_CHARACTERS "required_8469_01_characters_character_spell" - #define REVISION_DB_MANGOS "required_8499_01_mangos_spell_elixir" + #define REVISION_DB_CHARACTERS "required_8505_01_characters_character_spell" + #define REVISION_DB_MANGOS "required_8521_01_mangos_spell_proc_event" #define REVISION_DB_REALMD "required_8332_01_realmd_realmcharacters" #endif // __REVISION_SQL_H__