diff --git a/sql/characters.sql b/sql/characters.sql index 4c6bfed49..e26bff136 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_2008_11_07_03_characters_guild_bank_tab` bit(1) default NULL + `required_2008_11_12_01_character_character_aura` 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 18be4c83d..6a603bc4e 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -22,7 +22,7 @@ DROP TABLE IF EXISTS `db_version`; CREATE TABLE `db_version` ( `version` varchar(120) default NULL, - `required_2008_11_11_02_mangos_scripts` bit(1) default NULL + `required_2008_11_14_01_mangos_scripts` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- diff --git a/sql/updates/2008_11_12_01_character_character_aura.sql b/sql/updates/2008_11_12_01_character_character_aura.sql new file mode 100644 index 000000000..187a1f125 --- /dev/null +++ b/sql/updates/2008_11_12_01_character_character_aura.sql @@ -0,0 +1,5 @@ +ALTER TABLE character_db_version CHANGE COLUMN required_2008_11_07_03_characters_guild_bank_tab required_2008_11_12_01_character_character_aura bit; + +ALTER TABLE `character_aura` ADD `stackcount` INT NOT NULL DEFAULT '1' AFTER `effect_index` ; +ALTER TABLE `pet_aura` ADD `stackcount` INT NOT NULL DEFAULT '1' AFTER `effect_index` ; + diff --git a/sql/updates/2008_11_14_01_mangos_scripts.sql b/sql/updates/2008_11_14_01_mangos_scripts.sql new file mode 100644 index 000000000..ab51cf3d8 --- /dev/null +++ b/sql/updates/2008_11_14_01_mangos_scripts.sql @@ -0,0 +1,16 @@ +ALTER TABLE db_version CHANGE COLUMN required_2008_11_11_02_mangos_scripts required_2008_11_14_01_mangos_scripts bit; + +ALTER TABLE event_scripts + CHANGE COLUMN dataint dataint int(11) NOT NULL default '0' AFTER datalong2; + +ALTER TABLE gameobject_scripts + CHANGE COLUMN dataint dataint int(11) NOT NULL default '0' AFTER datalong2; + +ALTER TABLE quest_end_scripts + CHANGE COLUMN dataint dataint int(11) NOT NULL default '0' AFTER datalong2; + +ALTER TABLE quest_start_scripts + CHANGE COLUMN dataint dataint int(11) NOT NULL default '0' AFTER datalong2; + +ALTER TABLE spell_scripts + CHANGE COLUMN dataint dataint int(11) NOT NULL default '0' AFTER datalong2; diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index f5a13a33e..b743c6d15 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -132,6 +132,7 @@ pkgdata_DATA = \ 2008_11_09_03_mangos_mangos_string.sql \ 2008_11_11_01_mangos_db_script_string.sql \ 2008_11_11_02_mangos_scripts.sql \ + 2008_11_14_01_mangos_scripts.sql \ README ## Additional files to include when running 'make dist' @@ -245,4 +246,6 @@ EXTRA_DIST = \ 2008_11_09_03_mangos_mangos_string.sql \ 2008_11_11_01_mangos_db_script_string.sql \ 2008_11_11_02_mangos_scripts.sql \ + 2008_11_12_01_character_character_aura.sql \ + 2008_11_14_01_mangos_scripts.sql \ README diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index 512848107..75b85047a 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -62,7 +62,7 @@ bool LoginQueryHolder::Initialize() res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT leaderGuid FROM group_member WHERE memberGuid ='%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u' ORDER by spell,effect_index", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_index,stackcount,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLS, "SELECT spell,slot,active,disabled FROM character_spell WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS, "SELECT quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4 FROM character_queststatus WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS,"SELECT quest,time FROM character_queststatus_daily WHERE guid = '%u'", GUID_LOPART(m_guid)); diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 5c4a129ac..23023b2cb 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -6326,7 +6326,8 @@ bool ChatHandler::HandleSendMoneyCommand(const char* args) if (!msgText) return false; - int32 money = atoi(strtok(NULL, "")); + char* money_str = strtok(NULL, ""); + int32 money = money_str ? atoi(money_str) : 0; if (money <= 0) return false; diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 061fb0d31..9a69e199f 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -562,6 +562,63 @@ bool Map::loaded(const GridPair &p) const void Map::Update(const uint32 &t_diff) { + resetMarkedCells(); + + //TODO: Player guard + HashMapHolder::MapType& playerMap = HashMapHolder::GetContainer(); + for(HashMapHolder::MapType::iterator iter = playerMap.begin(); iter != playerMap.end(); ++iter) + { + WorldObject* obj = iter->second; + + if(!obj->IsInWorld()) + continue; + + if(obj->GetMapId() != GetId()) + continue; + + if(obj->GetInstanceId() != GetInstanceId()) + continue; + + CellPair standing_cell(MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY())); + + // Check for correctness of standing_cell, it also avoids problems with update_cell + if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + continue; + + // 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 + + 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) + markCell(x,y); + } + + MaNGOS::ObjectUpdater updater(t_diff); + // for creature + TypeContainerVisitor grid_object_update(updater); + // for pets + TypeContainerVisitor world_object_update(updater); + + for(int x = 0; x < TOTAL_NUMBER_OF_CELLS_PER_MAP; ++x) + { + for(int y = 0; y < TOTAL_NUMBER_OF_CELLS_PER_MAP; ++y) + { + if(isCellMarked(x,y)) + { + CellPair pair(x,y); + Cell cell(pair); + cell.data.Part.reserved = CENTER_DISTRICT; + cell.SetNoCreate(); + CellLock cell_lock(cell, pair); + cell_lock->Visit(cell_lock, grid_object_update, *this); + cell_lock->Visit(cell_lock, world_object_update, *this); + } + } + } + // Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load ! // This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended if (IsBattleGroundOrArena()) diff --git a/src/game/Map.h b/src/game/Map.h index 8ed6fa1f0..1647f3949 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -241,8 +241,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj void UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpair); void resetMarkedCells() { marked_cells.reset(); } - bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); } - void markCell(uint32 pCellId) { marked_cells.set(pCellId); } + bool isCellMarked(uint32 x, uint32 y) { return marked_cells.test(y * TOTAL_NUMBER_OF_CELLS_PER_MAP + x); } + void markCell(uint32 x, uint32 y) { marked_cells.set(y * TOTAL_NUMBER_OF_CELLS_PER_MAP + x); } private: void LoadVMap(int pX, int pY); void LoadMap(uint32 mapid, uint32 instanceid, int x,int y); diff --git a/src/game/MapManager.cpp b/src/game/MapManager.cpp index 6f04d2535..7e2fe8a61 100644 --- a/src/game/MapManager.cpp +++ b/src/game/MapManager.cpp @@ -245,6 +245,8 @@ MapManager::Update(time_t diff) if( !i_timer.Passed() ) return; + ObjectAccessor::Instance().UpdatePlayers(i_timer.GetCurrent()); + for(MapMapType::iterator iter=i_maps.begin(); iter != i_maps.end(); ++iter) { checkAndCorrectGridStatesArray(); // debugging code, should be deleted some day diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp index 61c92db3d..e35f808d7 100644 --- a/src/game/ObjectAccessor.cpp +++ b/src/game/ObjectAccessor.cpp @@ -247,32 +247,6 @@ ObjectAccessor::SaveAllPlayers() itr->second->SaveToDB(); } -void -ObjectAccessor::_update() -{ - UpdateDataMapType update_players; - { - Guard guard(i_updateGuard); - while(!i_objects.empty()) - { - Object* obj = *i_objects.begin(); - i_objects.erase(i_objects.begin()); - if (!obj) - continue; - _buildUpdateObject(obj, update_players); - obj->ClearUpdateMask(false); - } - } - - WorldPacket packet; // here we allocate a std::vector with a size of 0x10000 - for(UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter) - { - iter->second.BuildPacket(&packet); - iter->first->GetSession()->SendPacket(&packet); - packet.clear(); // clean the string - } -} - void ObjectAccessor::UpdateObject(Object* obj, Player* exceptPlayer) { @@ -513,72 +487,36 @@ ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid) void ObjectAccessor::Update(uint32 diff) { + UpdateDataMapType update_players; { - typedef std::multimap CreatureLocationHolderType; - CreatureLocationHolderType creature_locations; - //TODO: Player guard - HashMapHolder::MapType& playerMap = HashMapHolder::GetContainer(); - for(HashMapHolder::MapType::iterator iter = playerMap.begin(); iter != playerMap.end(); ++iter) + Guard guard(i_updateGuard); + while(!i_objects.empty()) { - if(iter->second->IsInWorld()) - { - iter->second->Update(diff); - creature_locations.insert( CreatureLocationHolderType::value_type(iter->second->GetMapId(), iter->second) ); - } - } - - Map *map; - - MaNGOS::ObjectUpdater updater(diff); - // for creature - TypeContainerVisitor grid_object_update(updater); - // for pets - TypeContainerVisitor world_object_update(updater); - - for(CreatureLocationHolderType::iterator iter=creature_locations.begin(); iter != creature_locations.end(); ++iter) - { - MapManager::Instance().GetMap((*iter).first, (*iter).second)->resetMarkedCells(); - } - - for(CreatureLocationHolderType::iterator iter=creature_locations.begin(); iter != creature_locations.end(); ++iter) - { - Player *player = (*iter).second; - map = MapManager::Instance().GetMap((*iter).first, player); - - CellPair standing_cell(MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY())); - - // Check for correctness of standing_cell, it also avoids problems with update_cell - if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + Object* obj = *i_objects.begin(); + i_objects.erase(i_objects.begin()); + if (!obj) continue; - - // 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 - - 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++) - { - uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; - if( !map->isCellMarked(cell_id) ) - { - CellPair cell_pair(x,y); - map->markCell(cell_id); - Cell cell(cell_pair); - cell.data.Part.reserved = CENTER_DISTRICT; - cell.SetNoCreate(); - CellLock cell_lock(cell, cell_pair); - cell_lock->Visit(cell_lock, grid_object_update, *map); - cell_lock->Visit(cell_lock, world_object_update, *map); - } - } - } + _buildUpdateObject(obj, update_players); + obj->ClearUpdateMask(false); } } - _update(); + WorldPacket packet; // here we allocate a std::vector with a size of 0x10000 + for(UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter) + { + iter->second.BuildPacket(&packet); + iter->first->GetSession()->SendPacket(&packet); + packet.clear(); // clean the string + } +} + +void +ObjectAccessor::UpdatePlayers(uint32 diff) +{ + HashMapHolder::MapType& playerMap = HashMapHolder::GetContainer(); + for(HashMapHolder::MapType::iterator iter = playerMap.begin(); iter != playerMap.end(); ++iter) + if(iter->second->IsInWorld()) + iter->second->Update(diff); } bool diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h index fbf60baaf..593b25a92 100644 --- a/src/game/ObjectAccessor.h +++ b/src/game/ObjectAccessor.h @@ -186,6 +186,7 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton i_objects; LockType i_playerGuard; LockType i_updateGuard; diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 60b3ce486..eef12f485 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -3757,11 +3757,8 @@ void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename) sLog.outErrorDb("Table `%s` has out of range text id (dataint = %i expected %u-%u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.dataint,MIN_DB_SCRIPT_STRING_ID,MAX_DB_SCRIPT_STRING_ID,tmp.id); continue; } - if(!objmgr.GetMangosStringLocale(tmp.dataint)) - { - sLog.outErrorDb("Table `%s` has not existed text id (dataint = %i) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.dataint,tmp.id); - continue; - } + + // if(!objmgr.GetMangosStringLocale(tmp.dataint)) will checked after db_script_string loading break; } @@ -7287,10 +7284,11 @@ void ObjectMgr::CheckScripts(ScriptMapMap const& scripts,std::set& ids) { if(itrM->second.dataint) { + if(!GetMangosStringLocale (itrM->second.dataint)) + sLog.outErrorDb( "Table `db_script_string` has not existed string id %u", *itrM); + if(ids.count(itrM->second.dataint)) ids.erase(itrM->second.dataint); - else - sLog.outErrorDb( "Table `db_script_string` has not existed string id %u", *itrM); } } } diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index fcbe055f2..466405175 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -1119,7 +1119,7 @@ void Pet::_LoadAuras(uint32 timediff) for (int i = 0; i < TOTAL_AURAS; i++) m_modAuras[i].clear(); - QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges FROM pet_aura WHERE guid = '%u'",m_charmInfo->GetPetNumber()); + QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,spell,effect_index,stackcount,amount,maxduration,remaintime,remaincharges FROM pet_aura WHERE guid = '%u'",m_charmInfo->GetPetNumber()); if(result) { @@ -1129,10 +1129,11 @@ void Pet::_LoadAuras(uint32 timediff) uint64 caster_guid = fields[0].GetUInt64(); uint32 spellid = fields[1].GetUInt32(); uint32 effindex = fields[2].GetUInt32(); - int32 damage = (int32)fields[3].GetUInt32(); - int32 maxduration = (int32)fields[4].GetUInt32(); - int32 remaintime = (int32)fields[5].GetUInt32(); - int32 remaincharges = (int32)fields[6].GetUInt32(); + uint32 stackcount= fields[3].GetUInt32(); + int32 damage = (int32)fields[4].GetUInt32(); + int32 maxduration = (int32)fields[5].GetUInt32(); + int32 remaintime = (int32)fields[6].GetUInt32(); + int32 remaincharges = (int32)fields[7].GetUInt32(); SpellEntry const* spellproto = sSpellStore.LookupEntry(spellid); if(!spellproto) @@ -1169,12 +1170,15 @@ void Pet::_LoadAuras(uint32 timediff) if (caster_guid != GetGUID() && IsSingleTargetSpell(spellproto)) continue; - Aura* aura = CreateAura(spellproto, effindex, NULL, this, NULL); + for(uint32 i=0; iGetModifier()->m_amount; - aura->SetLoadedState(caster_guid,damage,maxduration,remaintime,remaincharges); - AddAura(aura); + if(!damage) + damage = aura->GetModifier()->m_amount; + aura->SetLoadedState(caster_guid,damage,maxduration,remaintime,remaincharges); + AddAura(aura); + } } while( result->NextRow() ); @@ -1187,30 +1191,52 @@ void Pet::_SaveAuras() CharacterDatabase.PExecute("DELETE FROM pet_aura WHERE guid = '%u'", m_charmInfo->GetPetNumber()); AuraMap const& auras = GetAuras(); - for(AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + if (auras.empty()) + return; + + spellEffectPair lastEffectPair = auras.begin()->first; + uint32 stackCounter = 1; + + for(AuraMap::const_iterator itr = auras.begin(); ; ++itr) { - // skip all auras from spell that apply at cast SPELL_AURA_MOD_SHAPESHIFT or pet area auras. - SpellEntry const *spellInfo = itr->second->GetSpellProto(); - uint8 i; - for (i = 0; i < 3; i++) - if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_STEALTH || - spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_OWNER || - spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PET ) + if(itr == auras.end() || lastEffectPair != itr->first) + { + AuraMap::const_iterator itr2 = itr; + // save previous spellEffectPair to db + itr2--; + SpellEntry const *spellInfo = itr2->second->GetSpellProto(); + /// do not save single target auras (unless they were cast by the player) + if (!(itr2->second->GetCasterGUID() != GetGUID() && IsSingleTargetSpell(spellInfo))) + { + if(!itr2->second->IsPassive()) + { + // skip all auras from spell that apply at cast SPELL_AURA_MOD_SHAPESHIFT or pet area auras. + uint8 i; + for (i = 0; i < 3; i++) + if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_STEALTH || + spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_OWNER || + spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PET ) + break; + + if (i == 3) + { + CharacterDatabase.PExecute("INSERT INTO pet_aura (guid,caster_guid,spell,effect_index,stackcount,amount,maxduration,remaintime,remaincharges) " + "VALUES ('%u', '" I64FMTD "', '%u', '%u', '%u', '%d', '%d', '%d', '%d')", + m_charmInfo->GetPetNumber(), itr2->second->GetCasterGUID(),(uint32)itr2->second->GetId(), (uint32)itr2->second->GetEffIndex(), stackCounter, itr2->second->GetModifier()->m_amount,int(itr2->second->GetAuraMaxDuration()),int(itr2->second->GetAuraDuration()),int(itr2->second->m_procCharges)); + } + } + } + if(itr == auras.end()) break; + } - if (i != 3) - continue; - - if(itr->second->IsPassive()) - continue; - - /// do not save single target auras (unless they were cast by the player) - if (itr->second->GetCasterGUID() != GetGUID() && IsSingleTargetSpell(spellInfo)) - continue; - - CharacterDatabase.PExecute("INSERT INTO pet_aura (guid,caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges) " - "VALUES ('%u', '" I64FMTD "', '%u', '%u', '%d', '%d', '%d', '%d')", - m_charmInfo->GetPetNumber(), itr->second->GetCasterGUID(),(uint32)(*itr).second->GetId(), (uint32)(*itr).second->GetEffIndex(),(*itr).second->GetModifier()->m_amount,int((*itr).second->GetAuraMaxDuration()),int((*itr).second->GetAuraDuration()),int((*itr).second->m_procCharges)); + if (lastEffectPair == itr->first) + stackCounter++; + else + { + lastEffectPair = itr->first; + stackCounter = 1; + } } } diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 76dd63e83..d6a889110 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -14160,7 +14160,7 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff) for (int i = 0; i < TOTAL_AURAS; i++) m_modAuras[i].clear(); - //QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'",GetGUIDLow()); + //QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,spell,effect_index,stackcount,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'",GetGUIDLow()); if(result) { @@ -14170,10 +14170,11 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff) uint64 caster_guid = fields[0].GetUInt64(); uint32 spellid = fields[1].GetUInt32(); uint32 effindex = fields[2].GetUInt32(); - int32 damage = (int32)fields[3].GetUInt32(); - int32 maxduration = (int32)fields[4].GetUInt32(); - int32 remaintime = (int32)fields[5].GetUInt32(); - int32 remaincharges = (int32)fields[6].GetUInt32(); + uint32 stackcount = fields[3].GetUInt32(); + int32 damage = (int32)fields[4].GetUInt32(); + int32 maxduration = (int32)fields[5].GetUInt32(); + int32 remaintime = (int32)fields[6].GetUInt32(); + int32 remaincharges = (int32)fields[7].GetUInt32(); SpellEntry const* spellproto = sSpellStore.LookupEntry(spellid); if(!spellproto) @@ -14210,11 +14211,15 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff) if (caster_guid != GetGUID() && IsSingleTargetSpell(spellproto)) continue; - Aura* aura = CreateAura(spellproto, effindex, NULL, this, NULL); - if(!damage) - damage = aura->GetModifier()->m_amount; - aura->SetLoadedState(caster_guid,damage,maxduration,remaintime,remaincharges); - AddAura(aura); + for(uint32 i=0; iGetModifier()->m_amount; + aura->SetLoadedState(caster_guid,damage,maxduration,remaintime,remaincharges); + AddAura(aura); + sLog.outString("Added aura spellid %u, effect %u", spellproto->Id, effindex); + } } while( result->NextRow() ); @@ -15253,31 +15258,54 @@ void Player::_SaveAuras() CharacterDatabase.PExecute("DELETE FROM character_aura WHERE guid = '%u'",GetGUIDLow()); AuraMap const& auras = GetAuras(); - for(AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + + if (auras.empty()) + return; + + spellEffectPair lastEffectPair = auras.begin()->first; + uint32 stackCounter = 1; + + for(AuraMap::const_iterator itr = auras.begin(); ; ++itr) { - SpellEntry const *spellInfo = itr->second->GetSpellProto(); - - //skip all auras from spells that are passive or need a shapeshift - if (itr->second->IsPassive() || itr->second->IsRemovedOnShapeLost()) - continue; - - //do not save single target auras (unless they were cast by the player) - if (itr->second->GetCasterGUID() != GetGUID() && IsSingleTargetSpell(spellInfo)) - continue; - - uint8 i; - // or apply at cast SPELL_AURA_MOD_SHAPESHIFT or SPELL_AURA_MOD_STEALTH auras - for (i = 0; i < 3; i++) - if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT || - spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_STEALTH) - break; - - if (i == 3) + if(itr == auras.end() || lastEffectPair != itr->first) { - CharacterDatabase.PExecute("DELETE FROM character_aura WHERE guid = '%u' and spell = '%u' and effect_index= '%u'",GetGUIDLow(),(uint32)(*itr).second->GetId(), (uint32)(*itr).second->GetEffIndex()); - CharacterDatabase.PExecute("INSERT INTO character_aura (guid,caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges) " - "VALUES ('%u', '" I64FMTD "' ,'%u', '%u', '%d', '%d', '%d', '%d')", - GetGUIDLow(), itr->second->GetCasterGUID(), (uint32)(*itr).second->GetId(), (uint32)(*itr).second->GetEffIndex(), (*itr).second->GetModifier()->m_amount,int((*itr).second->GetAuraMaxDuration()),int((*itr).second->GetAuraDuration()),int((*itr).second->m_procCharges)); + AuraMap::const_iterator itr2 = itr; + // save previous spellEffectPair to db + itr2--; + SpellEntry const *spellInfo = itr2->second->GetSpellProto(); + + //skip all auras from spells that are passive or need a shapeshift + if (!(itr2->second->IsPassive() || itr2->second->IsRemovedOnShapeLost())) + { + //do not save single target auras (unless they were cast by the player) + if (!(itr2->second->GetCasterGUID() != GetGUID() && IsSingleTargetSpell(spellInfo))) + { + uint8 i; + // or apply at cast SPELL_AURA_MOD_SHAPESHIFT or SPELL_AURA_MOD_STEALTH auras + for (i = 0; i < 3; i++) + if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT || + spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_STEALTH) + break; + + if (i == 3) + { + CharacterDatabase.PExecute("INSERT INTO character_aura (guid,caster_guid,spell,effect_index,stackcount,amount,maxduration,remaintime,remaincharges) " + "VALUES ('%u', '" I64FMTD "' ,'%u', '%u', '%u', '%d', '%d', '%d', '%d')", + GetGUIDLow(), itr2->second->GetCasterGUID(), (uint32)itr2->second->GetId(), (uint32)itr2->second->GetEffIndex(), stackCounter, itr2->second->GetModifier()->m_amount,int(itr2->second->GetAuraMaxDuration()),int(itr2->second->GetAuraDuration()),int(itr2->second->m_procCharges)); + } + } + } + + if(itr == auras.end()) + break; + } + + if (lastEffectPair == itr->first) + stackCounter++; + else + { + lastEffectPair = itr->first; + stackCounter = 1; } } } diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 39325fbe2..0b6da451d 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -4590,8 +4590,10 @@ void Unit::CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, SpellSchool ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, damageSchoolMask, spellCasted, isTriggeredSpell, attType); } -bool Unit::HandleHasteAuraProc(Unit *pVictim, SpellEntry const *hasteSpell, uint32 /*effIndex*/, uint32 damage, Aura* triggeredByAura, SpellEntry const * /*procSpell*/, uint32 /*procFlag*/, uint32 cooldown) +bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * /*procSpell*/, uint32 /*procFlag*/, uint32 cooldown) { + SpellEntry const *hasteSpell = triggeredByAura->GetSpellProto(); + Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; @@ -4651,8 +4653,11 @@ bool Unit::HandleHasteAuraProc(Unit *pVictim, SpellEntry const *hasteSpell, uint return true; } -bool Unit::HandleDummyAuraProc(Unit *pVictim, SpellEntry const *dummySpell, uint32 effIndex, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 cooldown) +bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 cooldown) { + SpellEntry const *dummySpell = triggeredByAura->GetSpellProto (); + uint32 effIndex = triggeredByAura->GetEffIndex (); + Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; @@ -6466,8 +6471,10 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB return true; } -bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, int32 scriptId, uint32 /*damage*/, Aura *triggeredByAura, SpellEntry const *procSpell, uint32 cooldown) +bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura *triggeredByAura, SpellEntry const *procSpell, uint32 cooldown) { + int32 scriptId = triggeredByAura->GetModifier()->m_miscvalue; + if(!pVictim || !pVictim->isAlive()) return false; @@ -10020,17 +10027,15 @@ bool Unit::isFrozen() const struct ProcTriggeredData { - ProcTriggeredData(SpellEntry const * _spellInfo, uint32 _spellParam, Aura* _triggeredByAura, uint32 _cooldown) - : spellInfo(_spellInfo), spellParam(_spellParam), triggeredByAura(_triggeredByAura), + ProcTriggeredData(Aura* _triggeredByAura, uint32 _cooldown) + : triggeredByAura(_triggeredByAura), triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura->GetId(),triggeredByAura->GetEffIndex())), cooldown(_cooldown) - {} + {} - SpellEntry const * spellInfo; - uint32 spellParam; - Aura* triggeredByAura; - Unit::spellEffectPair triggeredByAura_SpellPair; - uint32 cooldown; + Aura* triggeredByAura; // triggred aura, can be invalidate at triggered aura proccessing + Unit::spellEffectPair triggeredByAura_SpellPair; // spell pair, used for re-find aura (by pointer comparison in range) + uint32 cooldown; // possible hidden cooldown }; typedef std::list< ProcTriggeredData > ProcTriggeredList; @@ -10047,87 +10052,13 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag { next = i; ++next; - SpellEntry const *spellProto = (*i)->GetSpellProto(); - if(!spellProto) + Aura* i_aura = *i; + + uint32 cooldown; // returned at next line + if(!IsTriggeredAtSpellProcEvent(i_aura->GetSpellProto(), procSpell, procFlag,attType,isVictim,cooldown)) continue; - SpellProcEventEntry const *spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id); - if(!spellProcEvent) - { - // used to prevent spam in log about same non-handled spells - static std::set nonHandledSpellProcSet; - - if(spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end()) - { - sLog.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto->Id,(isVictim?"a victim's":"an attacker's")); - nonHandledSpellProcSet.insert(spellProto->Id); - } - - // spell.dbc use totally different flags, that only can create problems if used. - continue; - } - - // Check spellProcEvent data requirements - if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, procSpell,procFlag)) - continue; - - // Check if current equipment allows aura to proc - if(!isVictim && GetTypeId() == TYPEID_PLAYER ) - { - if(spellProto->EquippedItemClass == ITEM_CLASS_WEAPON) - { - Item *item = ((Player*)this)->GetWeaponForAttack(attType,true); - - if(!item || !((1<GetProto()->SubClass) & spellProto->EquippedItemSubClassMask)) - continue; - } - else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR) - { - // Check if player is wearing shield - Item *item = ((Player*)this)->GetShield(true); - if(!item || !((1<GetProto()->SubClass) & spellProto->EquippedItemSubClassMask)) - continue; - } - } - - float chance = (float)spellProto->procChance; - - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance); - - if(!isVictim && spellProcEvent->ppmRate != 0) - { - uint32 WeaponSpeed = GetAttackTime(attType); - chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate); - } - - if(roll_chance_f(chance)) - { - uint32 cooldown = spellProcEvent->cooldown; - - uint32 i_spell_eff = (*i)->GetEffIndex(); - - int32 i_spell_param; - switch(*aur) - { - case SPELL_AURA_PROC_TRIGGER_SPELL: - i_spell_param = procFlag; - break; - case SPELL_AURA_DUMMY: - case SPELL_AURA_PRAYER_OF_MENDING: - case SPELL_AURA_MOD_HASTE: - i_spell_param = i_spell_eff; - break; - case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: - i_spell_param = (*i)->GetModifier()->m_miscvalue; - break; - default: - i_spell_param = (*i)->GetModifier()->m_amount; - break; - } - - procTriggered.push_back( ProcTriggeredData(spellProto,i_spell_param,*i, cooldown) ); - } + procTriggered.push_back( ProcTriggeredData(i_aura, cooldown) ); } // Handle effects proceed this time @@ -10160,106 +10091,71 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag } } - // save charges existence before processing to prevent crash at access to deleted triggered aura after - bool triggeredByAuraWithCharges = i->triggeredByAura->m_procCharges > 0; + /// this is aura triggering code call + Aura* triggeredByAura = i->triggeredByAura; + /// save charges existence before processing to prevent crash at access to deleted triggered aura after + /// used in speedup code check before check aura existance. + bool triggeredByAuraWithCharges = triggeredByAura->m_procCharges > 0; + + /// success in event proccesing + /// used in speedup code check before check aura existance. bool casted = false; + + /// process triggered code switch(*aur) { case SPELL_AURA_PROC_TRIGGER_SPELL: { - sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); - casted = HandleProcTriggerSpell(pTarget, damage, i->triggeredByAura, procSpell,i->spellParam,attType,i->cooldown); + sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s proc aura of spell %u)", + (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); + casted = HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, attType, i->cooldown); break; } case SPELL_AURA_PROC_TRIGGER_DAMAGE: { - sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", i->spellParam, i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); - uint32 damage = i->spellParam; - SpellNonMeleeDamageLog(pTarget, i->spellInfo->Id, damage, true, true); + uint32 triggered_damage = triggeredByAura->GetModifier()->m_amount; + sLog.outDebug("ProcDamageAndSpell: doing %u damage (triggered by %s aura of spell %u)", + triggered_damage, (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); + SpellNonMeleeDamageLog(pTarget, triggeredByAura->GetId(), triggered_damage, true, true); casted = true; break; } case SPELL_AURA_DUMMY: { - sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); - casted = HandleDummyAuraProc(pTarget, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procFlag,i->cooldown); + uint32 effect = triggeredByAura->GetEffIndex(); + sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s dummy aura of spell %u)", + (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); + casted = HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag,i->cooldown); break; } case SPELL_AURA_PRAYER_OF_MENDING: { - sLog.outDebug("ProcDamageAndSpell(mending): casting spell id %u (triggered by %s dummy aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); + sLog.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)", + (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); - // aura can be deleted at casts - int32 heal = i->triggeredByAura->GetModifier()->m_amount; - uint64 caster_guid = i->triggeredByAura->GetCasterGUID(); - - // jumps - int32 jumps = i->triggeredByAura->m_procCharges-1; - - // current aura expire - i->triggeredByAura->m_procCharges = 1; // will removed at next charges decrease - - // next target selection - if(jumps > 0 && GetTypeId()==TYPEID_PLAYER && IS_PLAYER_GUID(caster_guid)) - { - Aura* aura = i->triggeredByAura; - - SpellEntry const* spellProto = aura->GetSpellProto(); - uint32 effIdx = aura->GetEffIndex(); - - float radius; - if (spellProto->EffectRadiusIndex[effIdx]) - radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellProto->EffectRadiusIndex[effIdx])); - else - radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(spellProto->rangeIndex)); - - if(Player* caster = ((Player*)aura->GetCaster())) - { - caster->ApplySpellMod(spellProto->Id, SPELLMOD_RADIUS, radius,NULL); - - if(Player* target = ((Player*)this)->GetNextRandomRaidMember(radius)) - { - // aura will applied from caster, but spell casted from current aura holder - SpellModifier *mod = new SpellModifier; - mod->op = SPELLMOD_CHARGES; - mod->value = jumps-5; // negative - mod->type = SPELLMOD_FLAT; - mod->spellId = spellProto->Id; - mod->effectId = effIdx; - mod->lastAffected = NULL; - mod->mask = spellProto->SpellFamilyFlags; - mod->charges = 0; - - caster->AddSpellMod(mod, true); - CastCustomSpell(target,spellProto->Id,&heal,NULL,NULL,true,NULL,aura,caster->GetGUID()); - caster->AddSpellMod(mod, false); - } - } - } - - // heal - CastCustomSpell(this,33110,&heal,NULL,NULL,true,NULL,NULL,caster_guid); - casted = true; + casted = HandleMeandingAuraProc(triggeredByAura); break; } case SPELL_AURA_MOD_HASTE: { - sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); - casted = HandleHasteAuraProc(pTarget, i->spellInfo, i->spellParam, damage, i->triggeredByAura, procSpell, procFlag,i->cooldown); + sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s haste aura of spell %u)", + (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); + casted = HandleHasteAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag,i->cooldown); break; } case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN: { // nothing do, just charges counter // but count only in case appropriate school damage - casted = i->triggeredByAura->GetModifier()->m_miscvalue & damageSchoolMask; + casted = triggeredByAura->GetModifier()->m_miscvalue & damageSchoolMask; break; } case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: { - sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", i->spellInfo->Id,(isVictim?"a victim's":"an attacker's"),i->triggeredByAura->GetId()); - casted = HandleOverrideClassScriptAuraProc(pTarget, i->spellParam, damage, i->triggeredByAura, procSpell,i->cooldown); + sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s class script aura of spell %u)", + (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); + casted = HandleOverrideClassScriptAuraProc(pTarget, triggeredByAura, procSpell,i->cooldown); break; } default: @@ -10270,27 +10166,27 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag } } - // Update charge (aura can be removed by triggers) + /// Update charge (aura can be removed by triggers) if(casted && triggeredByAuraWithCharges) { - // need found aura (can be dropped by triggers) + /// need re-found aura (can be dropped by triggers) AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair); AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair); for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr) { - if(itr->second == i->triggeredByAura) + if(itr->second == triggeredByAura) // pointer still valid { - if(i->triggeredByAura->m_procCharges > 0) - i->triggeredByAura->m_procCharges -= 1; + if(triggeredByAura->m_procCharges > 0) + triggeredByAura->m_procCharges -= 1; - i->triggeredByAura->UpdateAuraCharges(); + triggeredByAura->UpdateAuraCharges(); break; } } } } - // Safely remove auras with zero charges + /// Safely remove auras with zero charges for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next) { next = i; ++next; @@ -10911,3 +10807,112 @@ Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget,uint32 spell_id) return pet; } + +bool Unit::IsTriggeredAtSpellProcEvent(SpellEntry const* spellProto, SpellEntry const* procSpell, uint32 procFlag, WeaponAttackType attType, bool isVictim, uint32& cooldown ) +{ + SpellProcEventEntry const * spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id); + + if(!spellProcEvent) + { + // used to prevent spam in log about same non-handled spells + static std::set nonHandledSpellProcSet; + + if(spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end()) + { + sLog.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto->Id,(isVictim?"a victim's":"an attacker's")); + nonHandledSpellProcSet.insert(spellProto->Id); + } + + // spell.dbc use totally different flags, that only can create problems if used. + return false; + } + + // Check spellProcEvent data requirements + if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, procSpell,procFlag)) + return false; + + // Check if current equipment allows aura to proc + if(!isVictim && GetTypeId() == TYPEID_PLAYER ) + { + if(spellProto->EquippedItemClass == ITEM_CLASS_WEAPON) + { + Item *item = ((Player*)this)->GetWeaponForAttack(attType,true); + + if(!item || !((1<GetProto()->SubClass) & spellProto->EquippedItemSubClassMask)) + return false; + } + else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR) + { + // Check if player is wearing shield + Item *item = ((Player*)this)->GetShield(true); + if(!item || !((1<GetProto()->SubClass) & spellProto->EquippedItemSubClassMask)) + return false; + } + } + + float chance = (float)spellProto->procChance; + + if(Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance); + + if(!isVictim && spellProcEvent && spellProcEvent->ppmRate != 0) + { + uint32 WeaponSpeed = GetAttackTime(attType); + chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate); + } + + cooldown = spellProcEvent ? spellProcEvent->cooldown : 0; + return roll_chance_f(chance); +} + +bool Unit::HandleMeandingAuraProc( Aura* triggeredByAura ) +{ + // aura can be deleted at casts + SpellEntry const* spellProto = triggeredByAura->GetSpellProto(); + uint32 effIdx = triggeredByAura->GetEffIndex(); + int32 heal = triggeredByAura->GetModifier()->m_amount; + uint64 caster_guid = triggeredByAura->GetCasterGUID(); + + // jumps + int32 jumps = triggeredByAura->m_procCharges-1; + + // current aura expire + triggeredByAura->m_procCharges = 1; // will removed at next charges decrease + + // next target selection + if(jumps > 0 && GetTypeId()==TYPEID_PLAYER && IS_PLAYER_GUID(caster_guid)) + { + float radius; + if (spellProto->EffectRadiusIndex[effIdx]) + radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellProto->EffectRadiusIndex[effIdx])); + else + radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(spellProto->rangeIndex)); + + if(Player* caster = ((Player*)triggeredByAura->GetCaster())) + { + caster->ApplySpellMod(spellProto->Id, SPELLMOD_RADIUS, radius,NULL); + + if(Player* target = ((Player*)this)->GetNextRandomRaidMember(radius)) + { + // aura will applied from caster, but spell casted from current aura holder + SpellModifier *mod = new SpellModifier; + mod->op = SPELLMOD_CHARGES; + mod->value = jumps-5; // negative + mod->type = SPELLMOD_FLAT; + mod->spellId = spellProto->Id; + mod->effectId = effIdx; + mod->lastAffected = NULL; + mod->mask = spellProto->SpellFamilyFlags; + mod->charges = 0; + + caster->AddSpellMod(mod, true); + CastCustomSpell(target,spellProto->Id,&heal,NULL,NULL,true,NULL,triggeredByAura,caster->GetGUID()); + caster->AddSpellMod(mod, false); + } + } + } + + // heal + CastCustomSpell(this,33110,&heal,NULL,NULL,true,NULL,NULL,caster_guid); + return true; +} \ No newline at end of file diff --git a/src/game/Unit.h b/src/game/Unit.h index 5dd7c8e96..73580cc77 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1371,10 +1371,12 @@ class MANGOS_DLL_SPEC Unit : public WorldObject void SendAttackStart(Unit* pVictim); // only from Unit::AttackStart(Unit*) void ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, AuraTypeSet const& procAuraTypes, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage, SpellSchoolMask damageSchoolMask ); - bool HandleDummyAuraProc(Unit *pVictim, SpellEntry const *spellProto, uint32 effIndex, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag,uint32 cooldown); - bool HandleProcTriggerSpell(Unit *pVictim,uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags,WeaponAttackType attType,uint32 cooldown); - bool HandleHasteAuraProc(Unit *pVictim, SpellEntry const *spellProto, uint32 effIndex, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag,uint32 cooldown); - bool HandleOverrideClassScriptAuraProc(Unit *pVictim, int32 scriptId, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell,uint32 cooldown); + bool IsTriggeredAtSpellProcEvent( SpellEntry const* spellProto, SpellEntry const* procSpell, uint32 procFlag, WeaponAttackType attType, bool isVictim, uint32& cooldown ); + bool HandleDummyAuraProc( Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 procFlag, uint32 cooldown); + bool HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 procFlag, WeaponAttackType attType, uint32 cooldown); + bool HandleHasteAuraProc( Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 procFlag, uint32 cooldown); + bool HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 cooldown); + bool HandleMeandingAuraProc(Aura* triggeredByAura); uint32 m_state; // Even derived shouldn't modify uint32 m_CombatTimer; diff --git a/src/game/Vehicle.cpp b/src/game/Vehicle.cpp index 0955d80c3..374b083fc 100644 --- a/src/game/Vehicle.cpp +++ b/src/game/Vehicle.cpp @@ -83,9 +83,9 @@ bool Vehicle::Create(uint32 guidlow, Map *map, uint32 Entry, uint32 vehicleId, u SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); SetUInt32Value(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_UNKNOWN1); - SetUInt32Value(UNIT_FIELD_BYTES_1, 0x02000001); - SetUInt32Value(UNIT_FIELD_BYTES_2, 0x00000001); - SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 3.0f); + //SetUInt32Value(UNIT_FIELD_BYTES_1, 0x02000001); + //SetUInt32Value(UNIT_FIELD_BYTES_2, 0x00000001); + SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); CreatureInfo const *ci = GetCreatureInfo(); setFaction(team == ALLIANCE ? ci->faction_A : ci->faction_H); diff --git a/src/mangosd/Main.cpp b/src/mangosd/Main.cpp index 40706b19b..939afe0ca 100644 --- a/src/mangosd/Main.cpp +++ b/src/mangosd/Main.cpp @@ -26,6 +26,8 @@ #include "Log.h" #include "Master.h" #include "SystemConfig.h" +#include "revision.h" +#include "revision_nr.h" #ifdef WIN32 #include "ServiceWin32.h" @@ -51,6 +53,7 @@ uint32 realmID; ///< Id of the realm void usage(const char *prog) { sLog.outString("Usage: \n %s []\n" + " --version print version and exist\n\r" " -c config_file use config_file as configuration file\n\r" #ifdef WIN32 " Running as service functions:\n\r" @@ -86,6 +89,12 @@ extern int main(int argc, char **argv) cfg_file = argv[c]; } + if( strcmp(argv[c],"--version") == 0) + { + printf("%s\n", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID)); + return 0; + } + #ifdef WIN32 //////////// //Services// @@ -131,6 +140,22 @@ extern int main(int argc, char **argv) sLog.outError("Could not find configuration file %s.", cfg_file); return 1; } + + sLog.outString( "%s [world-daemon]", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID) ); + sLog.outString( " to stop.\n\n" ); + + sLog.outTitle( "MM MM MM MM MMMMM MMMM MMMMM"); + sLog.outTitle( "MM MM MM MM MMM MMM MM MM MMM MMM"); + sLog.outTitle( "MMM MMM MMM MM MMM MMM MM MM MMM"); + sLog.outTitle( "MM M MM MMMM MM MMM MM MM MMM"); + sLog.outTitle( "MM M MM MMMMM MM MMMM MMM MM MM MMM"); + sLog.outTitle( "MM M MM M MMM MM MMM MMMMMMM MM MM MMM"); + sLog.outTitle( "MM MM MMM MM MM MM MMM MM MM MMM"); + sLog.outTitle( "MM MM MMMMMMM MM MM MMM MMM MM MM MMM MMM"); + sLog.outTitle( "MM MM MM MMM MM MM MMMMMM MMMM MMMMM"); + sLog.outTitle( " MM MMM http://getmangos.com"); + sLog.outTitle( " MMMMMM\n\n"); + sLog.outString("Using configuration file %s.", cfg_file); ///- and run the 'Master' diff --git a/src/mangosd/Master.cpp b/src/mangosd/Master.cpp index cc8ab7381..4a01c10ab 100644 --- a/src/mangosd/Master.cpp +++ b/src/mangosd/Master.cpp @@ -32,8 +32,6 @@ #include "Timer.h" #include "Policies/SingletonImp.h" #include "SystemConfig.h" -#include "revision.h" -#include "revision_nr.h" #include "Config/ConfigEnv.h" #include "Database/DatabaseEnv.h" #include "CliRunnable.h" @@ -197,21 +195,6 @@ Master::~Master() /// Main function int Master::Run() { - sLog.outString( "%s [world-daemon]", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID) ); - sLog.outString( " to stop.\n\n" ); - - sLog.outTitle( "MM MM MM MM MMMMM MMMM MMMMM"); - sLog.outTitle( "MM MM MM MM MMM MMM MM MM MMM MMM"); - sLog.outTitle( "MMM MMM MMM MM MMM MMM MM MM MMM"); - sLog.outTitle( "MM M MM MMMM MM MMM MM MM MMM"); - sLog.outTitle( "MM M MM MMMMM MM MMMM MMM MM MM MMM"); - sLog.outTitle( "MM M MM M MMM MM MMM MMMMMMM MM MM MMM"); - sLog.outTitle( "MM MM MMM MM MM MM MMM MM MM MMM"); - sLog.outTitle( "MM MM MMMMMMM MM MM MMM MMM MM MM MMM MMM"); - sLog.outTitle( "MM MM MM MMM MM MM MMMMMM MMMM MMMMM"); - sLog.outTitle( " MM MMM http://getmangos.com"); - sLog.outTitle( " MMMMMM\n\n"); - /// worldd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if(!pidfile.empty()) diff --git a/src/realmd/Main.cpp b/src/realmd/Main.cpp index 0d691cd8c..930fd00a7 100644 --- a/src/realmd/Main.cpp +++ b/src/realmd/Main.cpp @@ -60,6 +60,7 @@ DatabaseType dbRealmServer; ///< Accessor to the void usage(const char *prog) { sLog.outString("Usage: \n %s []\n" + " --version print version and exist\n\r" " -c config_file use config_file as configuration file\n\r" #ifdef WIN32 " Running as service functions:\n\r" @@ -90,6 +91,12 @@ extern int main(int argc, char **argv) cfg_file = argv[c]; } + if( strcmp(argv[c],"--version") == 0) + { + printf("%s\n", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID)); + return 0; + } + #ifdef WIN32 //////////// //Services// @@ -135,6 +142,9 @@ extern int main(int argc, char **argv) sLog.outError("Could not find configuration file %s.", cfg_file); return 1; } + + sLog.outString( "%s [realm-daemon]", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID) ); + sLog.outString( " to stop.\n" ); sLog.outString("Using configuration file %s.", cfg_file); ///- Check the version of the configuration file @@ -151,9 +161,6 @@ extern int main(int argc, char **argv) while (pause > clock()) {} } - sLog.outString( "%s [realm-daemon]", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID) ); - sLog.outString( " to stop.\n" ); - /// realmd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if(!pidfile.empty()) diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 2bfc3feb3..264605f9f 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 "6818" + #define REVISION_NR "6824" #endif // __REVISION_NR_H__