diff --git a/sql/characters.sql b/sql/characters.sql index fc717c1ef..0be0021a5 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_7903_01_characters_character_pet` bit(1) default NULL + `required_7932_01_characters_character_pet` 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 8519835b6..8ec8fe716 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `db_version`; CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, - `required_7908_03_mangos_creature_template_addon` bit(1) default NULL + `required_7945_01_mangos_quest_template` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -13264,12 +13264,20 @@ CREATE TABLE `quest_template` ( `DetailsEmote2` smallint(5) unsigned NOT NULL default '0', `DetailsEmote3` smallint(5) unsigned NOT NULL default '0', `DetailsEmote4` smallint(5) unsigned NOT NULL default '0', + `DetailsEmoteDelay1` int(11) unsigned NOT NULL default '0', + `DetailsEmoteDelay2` int(11) unsigned NOT NULL default '0', + `DetailsEmoteDelay3` int(11) unsigned NOT NULL default '0', + `DetailsEmoteDelay4` int(11) unsigned NOT NULL default '0', `IncompleteEmote` smallint(5) unsigned NOT NULL default '0', `CompleteEmote` smallint(5) unsigned NOT NULL default '0', `OfferRewardEmote1` smallint(5) unsigned NOT NULL default '0', `OfferRewardEmote2` smallint(5) unsigned NOT NULL default '0', `OfferRewardEmote3` smallint(5) unsigned NOT NULL default '0', `OfferRewardEmote4` smallint(5) unsigned NOT NULL default '0', + `OfferRewardEmoteDelay1` int(11) unsigned NOT NULL default '0', + `OfferRewardEmoteDelay2` int(11) unsigned NOT NULL default '0', + `OfferRewardEmoteDelay3` int(11) unsigned NOT NULL default '0', + `OfferRewardEmoteDelay4` int(11) unsigned NOT NULL default '0', `StartScript` mediumint(8) unsigned NOT NULL default '0', `CompleteScript` mediumint(8) unsigned NOT NULL default '0', PRIMARY KEY (`entry`) diff --git a/sql/realmd.sql b/sql/realmd.sql index dfc329fd0..f534432c3 100644 --- a/sql/realmd.sql +++ b/sql/realmd.sql @@ -21,7 +21,7 @@ DROP TABLE IF EXISTS `realmd_db_version`; CREATE TABLE `realmd_db_version` ( - `required_7867_01_realmd_account` bit(1) default NULL + `required_7938_01_realmd_account` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB'; -- @@ -41,7 +41,7 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `account`; CREATE TABLE `account` ( - `id` bigint(20) unsigned NOT NULL auto_increment COMMENT 'Identifier', + `id` int(11) unsigned NOT NULL auto_increment COMMENT 'Identifier', `username` varchar(32) NOT NULL default '', `sha_pass_hash` varchar(40) NOT NULL default '', `gmlevel` tinyint(3) unsigned NOT NULL default '0', diff --git a/sql/updates/7932_01_characters_character_pet.sql b/sql/updates/7932_01_characters_character_pet.sql new file mode 100644 index 000000000..665f15bd5 --- /dev/null +++ b/sql/updates/7932_01_characters_character_pet.sql @@ -0,0 +1,9 @@ +ALTER TABLE character_db_version CHANGE COLUMN required_7903_01_characters_character_pet required_7932_01_characters_character_pet bit; + +UPDATE character_pet + SET abdata = CONCAT(REPLACE(TRIM(abdata),' ',' '),' '); + +UPDATE character_pet + SET abdata = SUBSTRING_INDEX(SUBSTRING_INDEX(abdata,' ',(10-3)*2),' ',-(10-3-3)*2) + WHERE length(SUBSTRING_INDEX(abdata, ' ', 20)) < length(abdata) and length(SUBSTRING_INDEX(abdata, ' ', 21)) >= length(abdata); + diff --git a/sql/updates/7938_01_realmd_account.sql b/sql/updates/7938_01_realmd_account.sql new file mode 100644 index 000000000..e0658b68c --- /dev/null +++ b/sql/updates/7938_01_realmd_account.sql @@ -0,0 +1,4 @@ +ALTER TABLE realmd_db_version CHANGE COLUMN required_7867_01_realmd_account required_7938_01_realmd_account bit; + +ALTER TABLE account + CHANGE id id int(11) unsigned NOT NULL auto_increment COMMENT 'Identifier'; \ No newline at end of file diff --git a/sql/updates/7945_01_mangos_quest_template.sql b/sql/updates/7945_01_mangos_quest_template.sql new file mode 100644 index 000000000..2c4b9a301 --- /dev/null +++ b/sql/updates/7945_01_mangos_quest_template.sql @@ -0,0 +1,11 @@ +ALTER TABLE db_version CHANGE COLUMN required_7908_03_mangos_creature_template_addon required_7945_01_mangos_quest_template bit; + +ALTER TABLE quest_template + ADD COLUMN `DetailsEmoteDelay1` int(11) unsigned NOT NULL default '0' AFTER `DetailsEmote4`, + ADD COLUMN `DetailsEmoteDelay2` int(11) unsigned NOT NULL default '0' AFTER `DetailsEmoteDelay1`, + ADD COLUMN `DetailsEmoteDelay3` int(11) unsigned NOT NULL default '0' AFTER `DetailsEmoteDelay2`, + ADD COLUMN `DetailsEmoteDelay4` int(11) unsigned NOT NULL default '0' AFTER `DetailsEmoteDelay3`, + ADD COLUMN `OfferRewardEmoteDelay1` int(11) unsigned NOT NULL default '0' AFTER `OfferRewardEmote4`, + ADD COLUMN `OfferRewardEmoteDelay2` int(11) unsigned NOT NULL default '0' AFTER `OfferRewardEmoteDelay1`, + ADD COLUMN `OfferRewardEmoteDelay3` int(11) unsigned NOT NULL default '0' AFTER `OfferRewardEmoteDelay2`, + ADD COLUMN `OfferRewardEmoteDelay4` int(11) unsigned NOT NULL default '0' AFTER `OfferRewardEmoteDelay3`; diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index acd664849..f8f1332a6 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -208,6 +208,9 @@ pkgdata_DATA = \ 7908_01_mangos_creature_template.sql \ 7908_02_mangos_creature_addon.sql \ 7908_03_mangos_creature_template_addon.sql \ + 7932_01_characters_character_pet.sql \ + 7938_01_realmd_account.sql \ + 7945_01_mangos_quest_template.sql \ README ## Additional files to include when running 'make dist' @@ -396,4 +399,7 @@ EXTRA_DIST = \ 7908_01_mangos_creature_template.sql \ 7908_02_mangos_creature_addon.sql \ 7908_03_mangos_creature_template_addon.sql \ + 7932_01_characters_character_pet.sql \ + 7938_01_realmd_account.sql \ + 7945_01_mangos_quest_template.sql \ README diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index a4598b1a2..b24bc8ad2 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -78,6 +78,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) switch(criteria->requiredType) { + case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: @@ -90,6 +91,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) switch(dataType) { case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE: + case ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE: return true; case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE: if(!creature.id || !objmgr.GetCreatureTemplate(creature.id)) @@ -174,7 +176,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) return false; } -bool AchievementCriteriaData::Meets(Player const* source, Unit const* target) const +bool AchievementCriteriaData::Meets(Player const* source, Unit const* target, uint32 miscvalue1 /*= 0*/) const { switch(dataType) { @@ -213,15 +215,17 @@ bool AchievementCriteriaData::Meets(Player const* source, Unit const* target) co } case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA: return target && target->HasAura(aura.spell_id,aura.effect_idx); + case ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE: + return miscvalue1 >= value.minvalue; } return false; } -bool AchievementCriteriaDataSet::Meets(Player const* source, Unit const* target) const +bool AchievementCriteriaDataSet::Meets(Player const* source, Unit const* target, uint32 miscvalue /*= 0*/) const { for(Storage::const_iterator itr = storage.begin(); itr != storage.end(); ++itr) - if(!itr->Meets(source,target)) + if(!itr->Meets(source,target,miscvalue)) return false; return true; @@ -289,6 +293,11 @@ void AchievementMgr::ResetAchievementCriteria(AchievementCriteriaTypes type, uin achievementCriteria->healing_done.mapid == miscvalue2) SetCriteriaProgress(achievementCriteria, 0, PROGRESS_SET); break; + case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: // have total statistic also not expected to be reset + // reset only the criteria having the miscvalue1 condition + if (achievementCriteria->win_rated_arena.flag == miscvalue1) + SetCriteriaProgress(achievementCriteria, 0, PROGRESS_SET); + break; default: // reset all cases break; } @@ -924,6 +933,26 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui continue; SetCriteriaProgress(achievementCriteria, GetPlayer()->GetItemCount(achievementCriteria->own_item.itemID, true)); break; + case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: + // miscvalue1 contains the personal rating + if (!miscvalue1) // no update at login + continue; + + // additional requirements + if(achievementCriteria->win_rated_arena.flag==ACHIEVEMENT_CRITERIA_CONDITION_NO_LOOSE) + { + // those requirements couldn't be found in the dbc + AchievementCriteriaDataSet const* data = achievementmgr.GetCriteriaDataSet(achievementCriteria); + if(!data || !data->Meets(GetPlayer(),unit,miscvalue1)) + { + // reset the progress as we have a win without the requirement. + SetCriteriaProgress(achievementCriteria, 0); + continue; + } + } + + SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); + break; case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case if(!miscvalue1) @@ -1189,7 +1218,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA: case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING: case ACHIEVEMENT_CRITERIA_TYPE_REACH_TEAM_RATING: case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK: @@ -1295,6 +1323,8 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve return progress->counter >= 1; case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM: return progress->counter >= achievementCriteria->own_item.itemCount; + case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: + return progress->counter >= achievementCriteria->win_rated_arena.count; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL: return progress->counter >= (achievementCriteria->learn_skill_level.skillLevel * 75); case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: @@ -1748,6 +1778,10 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData() switch(criteria->requiredType) { + case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: // need skip generic cases + if(criteria->win_rated_arena.flag!=ACHIEVEMENT_CRITERIA_CONDITION_NO_LOOSE) + continue; + break; case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: // need skip generic cases if(criteria->do_emote.count==0) continue; diff --git a/src/game/AchievementMgr.h b/src/game/AchievementMgr.h index 0749beb16..14ca857ab 100644 --- a/src/game/AchievementMgr.h +++ b/src/game/AchievementMgr.h @@ -50,9 +50,10 @@ enum AchievementCriteriaDataType ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA = 5, // spell_id effect_idx ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA = 6, // area id 0 ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA = 7, // spell_id effect_idx + ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE = 8, // minvalue value provided with achievement update must be not less that limit }; -#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 8 // maximum value in AchievementCriteriaDataType enum +#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 9 // maximum value in AchievementCriteriaDataType enum class Player; class Unit; @@ -95,6 +96,11 @@ struct AchievementCriteriaData { uint32 id; } area; + // ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE + struct + { + uint32 minvalue; + } value; // ... struct { @@ -116,14 +122,14 @@ struct AchievementCriteriaData } bool IsValid(AchievementCriteriaEntry const* criteria); - bool Meets(Player const* source, Unit const* target) const; + bool Meets(Player const* source, Unit const* target, uint32 miscvalue1 = 0) const; }; struct AchievementCriteriaDataSet { typedef std::vector Storage; void Add(AchievementCriteriaData const& data) { storage.push_back(data); } - bool Meets(Player const* source, Unit const* target) const; + bool Meets(Player const* source, Unit const* target, uint32 miscvalue = 0) const; private: Storage storage; }; diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index bc0b7a58e..fe7a00a5d 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -697,9 +697,19 @@ void BattleGround::EndBattleGround(uint32 winner) if (isArena() && isRated() && winner_arena_team && loser_arena_team) { if (team == winner) + { + // update achievement BEFORE personal rating update + plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA, winner_arena_team->GetMember(plr->GetGUID())->personal_rating); + winner_arena_team->MemberWon(plr,loser_rating); + } else + { loser_arena_team->MemberLost(plr,winner_rating); + + // Arena lost => reset the win_rated_arena having the "no_loose" condition + plr->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA, ACHIEVEMENT_CRITERIA_CONDITION_NO_LOOSE); + } } if (team == winner) diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index 6490163ca..75d2ad96b 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -951,6 +951,9 @@ void GameObject::Use(Unit* user) // possible quest objective for active quests player->CastedCreatureOrGO(info->id, GetGUID(), 0); + + if (info->goober.eventId) + sWorld.ScriptsStart(sEventScripts, info->goober.eventId, player, this); } // cast this spell later if provided @@ -972,6 +975,9 @@ void GameObject::Use(Unit* user) if (info->camera.cinematicId) player->SendCinematicStart(info->camera.cinematicId); + if (info->camera.eventID) + sWorld.ScriptsStart(sEventScripts, info->camera.eventID, player, this); + return; } //fishing bobber diff --git a/src/game/GossipDef.cpp b/src/game/GossipDef.cpp index ccddbdbc7..ab229d9f1 100644 --- a/src/game/GossipDef.cpp +++ b/src/game/GossipDef.cpp @@ -504,7 +504,7 @@ void PlayerMenu::SendQuestGiverQuestDetails( Quest const *pQuest, uint64 npcGUID for (uint32 i=0; i < QUEST_EMOTE_COUNT; ++i) { data << uint32(pQuest->DetailsEmote[i]); - data << uint32(0); // DetailsEmoteDelay + data << uint32(pQuest->DetailsEmoteDelay[i]); // DetailsEmoteDelay (in ms) } pSession->SendPacket( &data ); @@ -642,7 +642,7 @@ void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest ) sLog.outDebug( "WORLD: Sent SMSG_QUEST_QUERY_RESPONSE questid=%u", pQuest->GetQuestId() ); } -void PlayerMenu::SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID, bool EnbleNext ) +void PlayerMenu::SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID, bool EnableNext ) { std::string Title = pQuest->GetTitle(); std::string OfferRewardText = pQuest->GetOfferRewardText(); @@ -667,7 +667,7 @@ void PlayerMenu::SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID, data << Title; data << OfferRewardText; - data << uint32( EnbleNext ); + data << uint32( EnableNext ); data << uint32(0); // unk uint32 EmoteCount = 0; @@ -681,8 +681,8 @@ void PlayerMenu::SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID, data << EmoteCount; // Emote Count for (uint32 i = 0; i < EmoteCount; ++i) { - data << uint32(0); // Delay Emote - data << pQuest->OfferRewardEmote[i]; + data << uint32(pQuest->OfferRewardEmoteDelay[i]); // Delay Emote + data << uint32(pQuest->OfferRewardEmote[i]); } ItemPrototype const *pItem; diff --git a/src/game/LootMgr.cpp b/src/game/LootMgr.cpp index e975fe78b..276116933 100644 --- a/src/game/LootMgr.cpp +++ b/src/game/LootMgr.cpp @@ -1330,7 +1330,7 @@ void LoadLootTemplates_Spell() } // output error for any still listed (not referenced from appropriate table) ids - LootTemplates_QuestMail.ReportUnusedIds(ids_set); + LootTemplates_Spell.ReportUnusedIds(ids_set); } void LoadLootTemplates_Reference() diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp index abbebf648..45dc90bdd 100644 --- a/src/game/NPCHandler.cpp +++ b/src/game/NPCHandler.cpp @@ -155,7 +155,7 @@ void WorldSession::SendTrainerList( uint64 guid, const std::string& strTitle ) // reputation discount float fDiscountMod = _player->GetReputationPriceDiscount(unit); - bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProffesionPoints() > 0; + bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProfessionPoints() > 0; uint32 count = 0; for(TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr) diff --git a/src/game/Object.cpp b/src/game/Object.cpp index cfb55e19c..3200f6881 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -63,7 +63,7 @@ uint32 GuidHigh2TypeId(uint32 guid_hi) return NUM_CLIENT_OBJECT_TYPES; // unknown } -Object::Object( ) +Object::Object( ) : m_PackGUID(sizeof(uint64)+1) { m_objectTypeId = TYPEID_OBJECT; m_objectType = TYPEMASK_OBJECT; @@ -75,7 +75,6 @@ Object::Object( ) m_inWorld = false; m_objectUpdated = false; - m_PackGUID.clear(); m_PackGUID.appendPackGUID(0); } @@ -118,7 +117,7 @@ void Object::_Create( uint32 guidlow, uint32 entry, HighGuid guidhigh ) uint64 guid = MAKE_NEW_GUID(guidlow, entry, guidhigh); SetUInt64Value( OBJECT_FIELD_GUID, guid ); SetUInt32Value( OBJECT_FIELD_TYPE, m_objectType ); - m_PackGUID.clear(); + m_PackGUID.wpos(0); m_PackGUID.appendPackGUID(GetGUID()); } diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index c41607065..c535077fa 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -2851,9 +2851,13 @@ void ObjectMgr::LoadQuests() "RewRepFaction1, RewRepFaction2, RewRepFaction3, RewRepFaction4, RewRepFaction5, RewRepValue1, RewRepValue2, RewRepValue3, RewRepValue4, RewRepValue5," // 97 98 99 100 101 102 103 104 105 106 107 "RewHonorableKills, RewOrReqMoney, RewMoneyMaxLevel, RewSpell, RewSpellCast, RewMailTemplateId, RewMailDelaySecs, PointMapId, PointX, PointY, PointOpt," - // 108 109 110 111 112 113 114 115 116 117 - "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4," - // 118 119 + // 108 109 110 111 112 113 114 115 + "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, DetailsEmoteDelay1, DetailsEmoteDelay2, DetailsEmoteDelay3, DetailsEmoteDelay4," + // 116 117 118 119 120 121 + "IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4," + // 122 123 124 125 + "OfferRewardEmoteDelay1, OfferRewardEmoteDelay2, OfferRewardEmoteDelay3, OfferRewardEmoteDelay4," + // 126 127 "StartScript, CompleteScript" " FROM quest_template"); if(result == NULL) @@ -3929,13 +3933,16 @@ void ObjectMgr::LoadEventScripts() switch(goInfo->type) { case GAMEOBJECT_TYPE_GOOBER: - if(goInfo->goober.eventId) + if (goInfo->goober.eventId) evt_scripts.insert(goInfo->goober.eventId); break; case GAMEOBJECT_TYPE_CHEST: - if(goInfo->chest.eventId) + if (goInfo->chest.eventId) evt_scripts.insert(goInfo->chest.eventId); break; + case GAMEOBJECT_TYPE_CAMERA: + if (goInfo->camera.eventID) + evt_scripts.insert(goInfo->camera.eventID); default: break; } @@ -3962,7 +3969,8 @@ void ObjectMgr::LoadEventScripts() { std::set::const_iterator itr2 = evt_scripts.find(itr->first); if (itr2 == evt_scripts.end()) - sLog.outErrorDb("Table `event_scripts` has script (Id: %u) not referring to any gameobject_template type 10 data2 field or type 3 data6 field or any spell effect %u", itr->first, SPELL_EFFECT_SEND_EVENT); + sLog.outErrorDb("Table `event_scripts` has script (Id: %u) not referring to any gameobject_template type 10 data2 field, type 3 data6 field, type 13 data 2 field or any spell effect %u", + itr->first, SPELL_EFFECT_SEND_EVENT); } } diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 40a19b95f..23a69d9f2 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -239,14 +239,9 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool CharacterDatabase.CommitTransaction(); } + // load action bar, if data broken will fill later by default spells. if (!is_temporary_summoned) - { - if(!m_charmInfo->LoadActionBar(fields[13].GetCppString())) - { - delete result; - return false; - } - } + m_charmInfo->LoadPetActionBar(fields[13].GetCppString()); // since last save (in seconds) uint32 timediff = (time(NULL) - fields[14].GetUInt32()); @@ -411,7 +406,8 @@ void Pet::SavePetToDB(PetSaveMode mode) << curmana << ", " << GetPower(POWER_HAPPINESS) << ", '"; - for(uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + // save only spell slots from action bar + for(uint32 i = ACTION_BAR_INDEX_PET_SPELL_START; i < ACTION_BAR_INDEX_PET_SPELL_END; ++i) { ss << uint32(m_charmInfo->GetActionBarEntry(i)->Type) << " " << uint32(m_charmInfo->GetActionBarEntry(i)->SpellOrAction) << " "; @@ -1093,17 +1089,7 @@ void Pet::_LoadSpells() { Field *fields = result->Fetch(); - uint32 spell_id = fields[0].GetUInt32(); - - // load only pet talents, other spell types auto-learned - if(GetTalentSpellCost(spell_id)==0) - { - CharacterDatabase.PExecute("DELETE FROM pet_spell WHERE spell = '%u'",spell_id); - sLog.outError("Table `pet_spell` have non-talent spell %u , spell removed from table for all pets.",spell_id); - continue; - } - - addSpell(spell_id, ActiveStates(fields[1].GetUInt16()), PETSPELL_UNCHANGED,PETSPELL_TALENT); + addSpell(fields[0].GetUInt32(), ActiveStates(fields[1].GetUInt16()), PETSPELL_UNCHANGED); } while( result->NextRow() ); @@ -1117,8 +1103,8 @@ void Pet::_SaveSpells() { ++next; - // save only talent spells for pets, other spells auto-applied - if (itr->second.type != PETSPELL_TALENT) + // prevent saving family passives to DB + if (itr->second.type == PETSPELL_FAMILY) continue; switch(itr->second.state) @@ -1329,9 +1315,6 @@ bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpel // talent: unlearn all other talent ranks (high and low) if(TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id)) { - // propertly mark spell for allow save - newspell.type = PETSPELL_TALENT; - if(TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentPos->talent_id )) { for(int i=0; i < MAX_TALENT_RANK; ++i) diff --git a/src/game/Pet.h b/src/game/Pet.h index 0ddc8fc56..55f679221 100644 --- a/src/game/Pet.h +++ b/src/game/Pet.h @@ -65,12 +65,11 @@ enum PetSpellType { PETSPELL_NORMAL = 0, PETSPELL_FAMILY = 1, - PETSPELL_TALENT = 2, }; struct PetSpell { - ActiveStates active : 16; + uint16 active; // use instead enum (not good use *uint16* limited enum in case when value in enum not possitive in *int16*) PetSpellState state : 8; PetSpellType type : 8; diff --git a/src/game/Player.cpp b/src/game/Player.cpp index af3b977f2..39585abe8 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -633,7 +633,7 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8 InitTaxiNodesForLevel(); InitGlyphsForLevel(); InitTalentForLevel(); - InitPrimaryProffesions(); // to max set before any spell added + InitPrimaryProfessions(); // to max set before any spell added // apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods() UpdateMaxHealth(); // Update max Health (for add bonus from stamina) @@ -2916,10 +2916,10 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen m_usedTalentCount += talentCost; // update free primary prof.points (if any, can be none in case GM .learn prof. learning) - if(uint32 freeProfs = GetFreePrimaryProffesionPoints()) + if(uint32 freeProfs = GetFreePrimaryProfessionPoints()) { if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell_id)) - SetFreePrimaryProffesions(freeProfs-1); + SetFreePrimaryProfessions(freeProfs-1); } // add dependent skills @@ -3119,9 +3119,9 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_ // update free primary prof.points (if not overflow setting, can be in case GM use before .learn prof. learning) if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell_id)) { - uint32 freeProfs = GetFreePrimaryProffesionPoints()+1; + uint32 freeProfs = GetFreePrimaryProfessionPoints()+1; if(freeProfs <= sWorld.getConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL)) - SetFreePrimaryProffesions(freeProfs); + SetFreePrimaryProfessions(freeProfs); } // remove dependent skill @@ -3744,7 +3744,7 @@ TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell return TRAINER_SPELL_GREEN; // check primary prof. limit - if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell->Id) && GetFreePrimaryProffesionPoints() == 0) + if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell->Id) && GetFreePrimaryProfessionPoints() == 0) return TRAINER_SPELL_GREEN_DISABLED; return TRAINER_SPELL_GREEN; @@ -13944,7 +13944,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) return false; } - InitPrimaryProffesions(); // to max set before any spell loaded + InitPrimaryProfessions(); // to max set before any spell loaded // init saved position, and fix it later if problematic uint32 transGUID = fields[24].GetUInt32(); @@ -16352,7 +16352,7 @@ void Player::PetSpellInitialize() CharmInfo *charmInfo = pet->GetCharmInfo(); - WorldPacket data(SMSG_PET_SPELLS, 8+2+4+4+4*10+1+1); + WorldPacket data(SMSG_PET_SPELLS, 8+2+4+4+4*MAX_UNIT_ACTION_BAR_INDEX+1+1); data << uint64(pet->GetGUID()); data << uint16(pet->GetCreatureInfo()->family); // creature family (required for pet talents) data << uint32(0); @@ -16426,7 +16426,7 @@ void Player::PossessSpellInitialize() return; } - WorldPacket data(SMSG_PET_SPELLS, 8+2+4+4+4*10+1+1); + WorldPacket data(SMSG_PET_SPELLS, 8+2+4+4+4*MAX_UNIT_ACTION_BAR_INDEX+1+1); data << uint64(charm->GetGUID()); data << uint16(0); data << uint32(0); @@ -16470,7 +16470,7 @@ void Player::CharmSpellInitialize() } } - WorldPacket data(SMSG_PET_SPELLS, 8+2+4+4+4*10+1+4*addlist+1); + WorldPacket data(SMSG_PET_SPELLS, 8+2+4+4+4*MAX_UNIT_ACTION_BAR_INDEX+1+4*addlist+1); data << uint64(charm->GetGUID()); data << uint16(0); data << uint32(0); @@ -17829,9 +17829,9 @@ template void Player::UpdateVisibilityOf(Corpse* target, UpdateData& data template void Player::UpdateVisibilityOf(GameObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); template void Player::UpdateVisibilityOf(DynamicObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); -void Player::InitPrimaryProffesions() +void Player::InitPrimaryProfessions() { - SetFreePrimaryProffesions(sWorld.getConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL)); + SetFreePrimaryProfessions(sWorld.getConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL)); } void Player::SendComboPoints() @@ -19269,7 +19269,7 @@ void Player::EnterVehicle(Vehicle *vehicle) data << uint32(0); // fall time GetSession()->SendPacket(&data); - data.Initialize(SMSG_PET_SPELLS, 8+2+4+4+4*10+1+1); + data.Initialize(SMSG_PET_SPELLS, 8+2+4+4+4*MAX_UNIT_ACTION_BAR_INDEX+1+1); data << uint64(vehicle->GetGUID()); data << uint16(0); data << uint32(0); diff --git a/src/game/Player.h b/src/game/Player.h index 655986cf0..2a07abec7 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1416,9 +1416,9 @@ class MANGOS_DLL_SPEC Player : public Unit void SetGlyph(uint8 slot, uint32 glyph) { SetUInt32Value(PLAYER_FIELD_GLYPHS_1 + slot, glyph); } uint32 GetGlyph(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_GLYPHS_1 + slot); } - uint32 GetFreePrimaryProffesionPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS2); } - void SetFreePrimaryProffesions(uint16 profs) { SetUInt32Value(PLAYER_CHARACTER_POINTS2, profs); } - void InitPrimaryProffesions(); + uint32 GetFreePrimaryProfessionPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS2); } + void SetFreePrimaryProfessions(uint16 profs) { SetUInt32Value(PLAYER_CHARACTER_POINTS2, profs); } + void InitPrimaryProfessions(); PlayerSpellMap const& GetSpellMap() const { return m_spells; } PlayerSpellMap & GetSpellMap() { return m_spells; } diff --git a/src/game/PlayerDump.cpp b/src/game/PlayerDump.cpp index 912c7519c..42a512689 100644 --- a/src/game/PlayerDump.cpp +++ b/src/game/PlayerDump.cpp @@ -335,16 +335,16 @@ std::string PlayerDumpWriter::GetDump(uint32 guid) dump += "IMPORTANT NOTE: NOT APPLY ITS DIRECTLY to character DB or you will DAMAGE and CORRUPT character DB\n\n"; // revision check guard - QueryResult* result = CharacterDatabase.Query("SELECT * FROM character_db_version LIMIT 1"); + QueryNamedResult* result = CharacterDatabase.QueryNamed("SELECT * FROM character_db_version LIMIT 1"); if(result) { - QueryResult::FieldNames const& namesMap = result->GetFieldNames(); + QueryFieldNames const& namesMap = result->GetFieldNames(); std::string reqName; - for(QueryResult::FieldNames::const_iterator itr = namesMap.begin(); itr != namesMap.end(); ++itr) + for(QueryFieldNames::const_iterator itr = namesMap.begin(); itr != namesMap.end(); ++itr) { - if(itr->second.substr(0,9)=="required_") + if(itr->substr(0,9)=="required_") { - reqName = itr->second; + reqName = *itr; break; } } diff --git a/src/game/QuestDef.cpp b/src/game/QuestDef.cpp index 2f0ed421c..8c71d83ac 100644 --- a/src/game/QuestDef.cpp +++ b/src/game/QuestDef.cpp @@ -115,14 +115,20 @@ Quest::Quest(Field * questRecord) for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) DetailsEmote[i] = questRecord[108+i].GetUInt32(); - IncompleteEmote = questRecord[112].GetUInt32(); - CompleteEmote = questRecord[113].GetUInt32(); + for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) + DetailsEmoteDelay[i] = questRecord[112+i].GetUInt32(); + + IncompleteEmote = questRecord[116].GetUInt32(); + CompleteEmote = questRecord[117].GetUInt32(); for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) - OfferRewardEmote[i] = questRecord[114+i].GetInt32(); + OfferRewardEmote[i] = questRecord[118+i].GetInt32(); - QuestStartScript = questRecord[118].GetUInt32(); - QuestCompleteScript = questRecord[119].GetUInt32(); + for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) + OfferRewardEmoteDelay[i] = questRecord[122+i].GetInt32(); + + QuestStartScript = questRecord[126].GetUInt32(); + QuestCompleteScript = questRecord[127].GetUInt32(); QuestFlags |= SpecialFlags << 16; diff --git a/src/game/QuestDef.h b/src/game/QuestDef.h index 82c9d7087..6a751c8bc 100644 --- a/src/game/QuestDef.h +++ b/src/game/QuestDef.h @@ -241,7 +241,9 @@ class Quest uint32 RewRepFaction[QUEST_REPUTATIONS_COUNT]; int32 RewRepValue[QUEST_REPUTATIONS_COUNT]; uint32 DetailsEmote[QUEST_EMOTE_COUNT]; + uint32 DetailsEmoteDelay[QUEST_EMOTE_COUNT]; uint32 OfferRewardEmote[QUEST_EMOTE_COUNT]; + uint32 OfferRewardEmoteDelay[QUEST_EMOTE_COUNT]; uint32 GetReqItemsCount() const { return m_reqitemscount; } uint32 GetReqCreatureOrGOcount() const { return m_reqCreatureOrGOcount; } diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 9d57a2947..24e1ec36f 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -3418,7 +3418,7 @@ void Aura::HandleAuraModStun(bool apply, bool Real) else { ((Player*)m_target)->m_movementInfo.flags = 0; // Clear movement flags - m_target->SetStandState(UNIT_STAND_STATE_STAND); + m_target->SetStandState(UNIT_STAND_STATE_STAND);// in 1.5 client } WorldPacket data(SMSG_FORCE_MOVE_ROOT, 8); diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 69ef4975a..45242d907 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -4042,6 +4042,8 @@ void Spell::EffectTameCreature(uint32 /*i*/) finish(); Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id); + if(!pet) // in versy specific state like near world end/etc. + return; // kill original creature creatureTarget->setDeathState(JUST_DIED); diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index f06073ee6..5ae4bd993 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -2719,6 +2719,13 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto return DIMINISHING_BLIND_CYCLONE; break; } + case SPELLFAMILY_HUNTER: + { + // Freezing trap + if (spellproto->SpellFamilyFlags & UI64LIT(0x00000000008)) + return DIMINISHING_FREEZE; + break; + } case SPELLFAMILY_WARLOCK: { // Fear diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index f0aec5ae2..49076c16f 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -8421,13 +8421,6 @@ bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo) if (!spellInfo) return false; - //FIX ME this hack: don't get feared if stunned - if (spellInfo->Mechanic == MECHANIC_FEAR ) - { - if ( hasUnitState(UNIT_STAT_STUNNED) ) - return true; - } - //TODO add spellEffect immunity checks!, player with flag in bg is imune to imunity buffs from other friendly players! //SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_EFFECT]; @@ -10325,21 +10318,22 @@ CharmInfo::CharmInfo(Unit* unit) void CharmInfo::InitPetActionBar() { // the first 3 SpellOrActions are attack, follow and stay - // last 3 SpellOrActions are reactions - for(uint32 i = 0; i < 3; ++i) - { - SetActionBar(i,COMMAND_ATTACK - i,ACT_COMMAND); - SetActionBar(i + 7,COMMAND_ATTACK - i,ACT_REACTION); - } + for(uint32 i = 0; i < ACTION_BAR_INDEX_PET_SPELL_START - ACTION_BAR_INDEX_START; ++i) + SetActionBar(ACTION_BAR_INDEX_START + i,COMMAND_ATTACK - i,ACT_COMMAND); + // middle 4 SpellOrActions are spells/special attacks/abilities - for(uint32 i = 0; i < 4; ++i) - SetActionBar(i + 3,0,ACT_DISABLED); + for(uint32 i = 0; i < ACTION_BAR_INDEX_PET_SPELL_END-ACTION_BAR_INDEX_PET_SPELL_START; ++i) + SetActionBar(ACTION_BAR_INDEX_PET_SPELL_START + i,0,ACT_DISABLED); + + // last 3 SpellOrActions are reactions + for(uint32 i = 0; i < ACTION_BAR_INDEX_END - ACTION_BAR_INDEX_PET_SPELL_END; ++i) + SetActionBar(ACTION_BAR_INDEX_PET_SPELL_END + i,COMMAND_ATTACK - i,ACT_REACTION); } void CharmInfo::InitEmptyActionBar() { - SetActionBar(0,COMMAND_ATTACK,ACT_COMMAND); - for(uint32 x = 1; x < MAX_UNIT_ACTION_BAR_INDEX; ++x) + SetActionBar(ACTION_BAR_INDEX_START,COMMAND_ATTACK,ACT_COMMAND); + for(uint32 x = ACTION_BAR_INDEX_START+1; x < ACTION_BAR_INDEX_END; ++x) SetActionBar(x,0,ACT_PASSIVE); } @@ -10476,16 +10470,18 @@ void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow) m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0); } -bool CharmInfo::LoadActionBar( std::string data ) +void CharmInfo::LoadPetActionBar( std::string data ) { + InitPetActionBar(); + Tokens tokens = StrSplit(data, " "); - if (tokens.size() != MAX_UNIT_ACTION_BAR_INDEX*2) - return false; + if (tokens.size() != (ACTION_BAR_INDEX_PET_SPELL_END-ACTION_BAR_INDEX_PET_SPELL_START)*2) + return; // non critical, will reset to default int index; Tokens::iterator iter; - for(iter = tokens.begin(), index = 0; index < MAX_UNIT_ACTION_BAR_INDEX; ++iter, ++index ) + for(iter = tokens.begin(), index = ACTION_BAR_INDEX_PET_SPELL_START; index < ACTION_BAR_INDEX_PET_SPELL_END; ++iter, ++index ) { // use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion PetActionBar[index].Type = atol((*iter).c_str()); @@ -10496,7 +10492,6 @@ bool CharmInfo::LoadActionBar( std::string data ) if(PetActionBar[index].IsActionBarForSpell() && !sSpellStore.LookupEntry(PetActionBar[index].SpellOrAction)) SetActionBar(index,0,ACT_DISABLED); } - return true; } void CharmInfo::BuildActionBar( WorldPacket* data ) diff --git a/src/game/Unit.h b/src/game/Unit.h index e5946c6e8..d6dac29c9 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -791,7 +791,15 @@ struct CharmSpellEntry uint16 active; }; -#define MAX_UNIT_ACTION_BAR_INDEX 10 +enum ActionBarIndex +{ + ACTION_BAR_INDEX_START = 0, + ACTION_BAR_INDEX_PET_SPELL_START = 3, + ACTION_BAR_INDEX_PET_SPELL_END = 7, + ACTION_BAR_INDEX_END = 10, +}; + +#define MAX_UNIT_ACTION_BAR_INDEX (ACTION_BAR_INDEX_END-ACTION_BAR_INDEX_START) struct CharmInfo { @@ -815,7 +823,7 @@ struct CharmInfo //return true if successful bool AddSpellToActionBar(uint32 spellid, ActiveStates newstate = ACT_DECIDE); bool RemoveSpellFromActionBar(uint32 spell_id); - bool LoadActionBar(std::string data); + void LoadPetActionBar(std::string data); void BuildActionBar(WorldPacket* data); void SetSpellAutocast(uint32 spell_id, bool state); void SetActionBar(uint8 index, uint32 spellOrAction,ActiveStates type) diff --git a/src/game/World.cpp b/src/game/World.cpp index be629090d..660ad1e46 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -2203,12 +2203,6 @@ void World::ScriptsProcess() break; } - if(!source->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_CAST_SPELL source caster isn't unit (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - Object* cmdTarget = step.script->datalong2 & 0x01 ? source : target; if(!cmdTarget) diff --git a/src/mangosd/Main.cpp b/src/mangosd/Main.cpp index 043e1c0b4..24c372b4e 100644 --- a/src/mangosd/Main.cpp +++ b/src/mangosd/Main.cpp @@ -28,6 +28,8 @@ #include "SystemConfig.h" #include "revision.h" #include "revision_nr.h" +#include +#include #ifdef WIN32 #include "ServiceWin32.h" @@ -158,6 +160,13 @@ extern int main(int argc, char **argv) sLog.outString("Using configuration file %s.", cfg_file); + sLog.outDetail("%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); + if (SSLeay() < 0x009080bfL ) + { + sLog.outDetail("WARNING: Outdated version of OpenSSL lib. Logins to server impossible!"); + sLog.outDetail("WARNING: Minimal required version [OpenSSL 0.9.8k]"); + } + ///- and run the 'Master' /// \todo Why do we need this 'Master'? Can't all of this be in the Main as for Realmd? return sMaster.Run(); diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.in index 7e94f4788..69643c7cf 100644 --- a/src/mangosd/mangosd.conf.dist.in +++ b/src/mangosd/mangosd.conf.dist.in @@ -976,10 +976,6 @@ Visibility.Distance.Grey.Object = 10 # Drop rates (items by quality and money) # Default: 1 # -# Rate.Drop.Money -# Drop rates -# Default: 1 -# # Rate.XP.Kill # Rate.XP.Quest # Rate.XP.Explore diff --git a/src/realmd/Main.cpp b/src/realmd/Main.cpp index 08611268e..777ad05c8 100644 --- a/src/realmd/Main.cpp +++ b/src/realmd/Main.cpp @@ -32,6 +32,8 @@ #include "revision.h" #include "revision_nr.h" #include "Util.h" +#include +#include #ifdef WIN32 #include "ServiceWin32.h" @@ -161,6 +163,13 @@ extern int main(int argc, char **argv) while (pause > clock()) {} } + sLog.outDetail("%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); + if (SSLeay() < 0x009080bfL ) + { + sLog.outDetail("WARNING: Outdated version of OpenSSL lib. Logins to server impossible!"); + sLog.outDetail("WARNING: Minimal required version [OpenSSL 0.9.8k]"); + } + /// realmd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if(!pidfile.empty()) diff --git a/src/shared/ByteBuffer.h b/src/shared/ByteBuffer.h index 5a13ea788..c289d34a7 100644 --- a/src/shared/ByteBuffer.h +++ b/src/shared/ByteBuffer.h @@ -309,11 +309,14 @@ class ByteBuffer } void append(const ByteBuffer& buffer) { - if(buffer.size()) append(buffer.contents(),buffer.size()); + if(buffer.size()) append(buffer.contents(),buffer.wpos()); } void appendPackGUID(uint64 guid) { + if (_storage.size() < _wpos + sizeof(guid) + 1) + _storage.resize(_wpos + sizeof(guid) + 1); + size_t mask_position = wpos(); *this << uint8(0); for(uint8 i = 0; i < 8; i++) diff --git a/src/shared/Database/Database.cpp b/src/shared/Database/Database.cpp index 84ef210db..58dc18c47 100644 --- a/src/shared/Database/Database.cpp +++ b/src/shared/Database/Database.cpp @@ -131,6 +131,25 @@ QueryResult* Database::PQuery(const char *format,...) return Query(szQuery); } +QueryNamedResult* Database::PQueryNamed(const char *format,...) +{ + if(!format) return NULL; + + va_list ap; + char szQuery [MAX_QUERY_LEN]; + va_start(ap, format); + int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap ); + va_end(ap); + + if(res==-1) + { + sLog.outError("SQL Query truncated (and not execute) for format: %s",format); + return false; + } + + return QueryNamed(szQuery); +} + bool Database::PExecute(const char * format,...) { if (!format) diff --git a/src/shared/Database/Database.h b/src/shared/Database/Database.h index c0d18e20b..fbfd4d6a5 100644 --- a/src/shared/Database/Database.h +++ b/src/shared/Database/Database.h @@ -52,6 +52,8 @@ class MANGOS_DLL_SPEC Database virtual QueryResult* Query(const char *sql) = 0; QueryResult* PQuery(const char *format,...) ATTR_PRINTF(2,3); + virtual QueryNamedResult* QueryNamed(const char *sql) = 0; + QueryNamedResult* PQueryNamed(const char *format,...) ATTR_PRINTF(2,3); /// Async queries and query holders, implemented in DatabaseImpl.h diff --git a/src/shared/Database/DatabaseMysql.cpp b/src/shared/Database/DatabaseMysql.cpp index 74efbf71b..1a56c1b64 100644 --- a/src/shared/Database/DatabaseMysql.cpp +++ b/src/shared/Database/DatabaseMysql.cpp @@ -176,15 +176,11 @@ bool DatabaseMysql::Initialize(const char *infoString) } } -QueryResult* DatabaseMysql::Query(const char *sql) +bool DatabaseMysql::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount) { if (!mMysql) return 0; - MYSQL_RES *result = 0; - uint64 rowCount = 0; - uint32 fieldCount = 0; - { // guarded block for thread-safe mySQL request ACE_Guard query_connection_guard(mMutex); @@ -195,7 +191,7 @@ QueryResult* DatabaseMysql::Query(const char *sql) { sLog.outErrorDb( "SQL: %s", sql ); sLog.outErrorDb("query ERROR: %s", mysql_error(mMysql)); - return NULL; + return false; } else { @@ -204,29 +200,63 @@ QueryResult* DatabaseMysql::Query(const char *sql) #endif } - result = mysql_store_result(mMysql); - - rowCount = mysql_affected_rows(mMysql); - fieldCount = mysql_field_count(mMysql); + *pResult = mysql_store_result(mMysql); + *pRowCount = mysql_affected_rows(mMysql); + *pFieldCount = mysql_field_count(mMysql); // end guarded block } - if (!result ) - return NULL; + if (!*pResult ) + return false; - if (!rowCount) + if (!*pRowCount) { - mysql_free_result(result); - return NULL; + mysql_free_result(*pResult); + return false; } - QueryResultMysql *queryResult = new QueryResultMysql(result, rowCount, fieldCount); + *pFields = mysql_fetch_fields(*pResult); + return true; +} + +QueryResult* DatabaseMysql::Query(const char *sql) +{ + MYSQL_RES *result = NULL; + MYSQL_FIELD *fields = NULL; + uint64 rowCount = 0; + uint32 fieldCount = 0; + + if(!_Query(sql,&result,&fields,&rowCount,&fieldCount)) + return NULL; + + QueryResultMysql *queryResult = new QueryResultMysql(result, fields, rowCount, fieldCount); queryResult->NextRow(); return queryResult; } +QueryNamedResult* DatabaseMysql::QueryNamed(const char *sql) +{ + MYSQL_RES *result = NULL; + MYSQL_FIELD *fields = NULL; + uint64 rowCount = 0; + uint32 fieldCount = 0; + + if(!_Query(sql,&result,&fields,&rowCount,&fieldCount)) + return NULL; + + QueryFieldNames names(fieldCount); + for (uint32 i = 0; i < fieldCount; i++) + names[i] = fields[i].name; + + QueryResultMysql *queryResult = new QueryResultMysql(result, fields, rowCount, fieldCount); + + queryResult->NextRow(); + + return new QueryNamedResult(queryResult,names); +} + bool DatabaseMysql::Execute(const char *sql) { if (!mMysql) diff --git a/src/shared/Database/DatabaseMysql.h b/src/shared/Database/DatabaseMysql.h index e00fbb60b..c2eee285a 100644 --- a/src/shared/Database/DatabaseMysql.h +++ b/src/shared/Database/DatabaseMysql.h @@ -48,6 +48,7 @@ class MANGOS_DLL_SPEC DatabaseMysql : public Database void InitDelayThread(); void HaltDelayThread(); QueryResult* Query(const char *sql); + QueryNamedResult* QueryNamed(const char *sql); bool Execute(const char *sql); bool DirectExecute(const char* sql); bool BeginTransaction(); @@ -73,6 +74,7 @@ class MANGOS_DLL_SPEC DatabaseMysql : public Database static size_t db_count; bool _TransactionCmd(const char *sql); + bool _Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount); }; #endif #endif diff --git a/src/shared/Database/DatabasePostgre.cpp b/src/shared/Database/DatabasePostgre.cpp index 2e0ef0890..55b60be5a 100644 --- a/src/shared/Database/DatabasePostgre.cpp +++ b/src/shared/Database/DatabasePostgre.cpp @@ -115,32 +115,27 @@ bool DatabasePostgre::Initialize(const char *infoString) } -QueryResult* DatabasePostgre::Query(const char *sql) +bool DatabasePostgre::_Query(const char *sql, PGresult** pResult, uint64* pRowCount, uint32* pFieldCount) { if (!mPGconn) return 0; - uint64 rowCount = 0; - uint32 fieldCount = 0; - // guarded block for thread-safe request ACE_Guard query_connection_guard(mMutex); #ifdef MANGOS_DEBUG uint32 _s = getMSTime(); #endif // Send the query - PGresult * result = PQexec(mPGconn, sql); - if (!result ) - { - return NULL; - } + *pResult = PQexec(mPGconn, sql); + if(!*pResult ) + return false; - if (PQresultStatus(result) != PGRES_TUPLES_OK) + if (PQresultStatus(*pResult) != PGRES_TUPLES_OK) { sLog.outErrorDb( "SQL : %s", sql ); sLog.outErrorDb( "SQL %s", PQerrorMessage(mPGconn)); - PQclear(result); - return NULL; + PQclear(*pResult); + return false; } else { @@ -149,15 +144,29 @@ QueryResult* DatabasePostgre::Query(const char *sql) #endif } - rowCount = PQntuples(result); - fieldCount = PQnfields(result); + *pRowCount = PQntuples(*pResult); + *pFieldCount = PQnfields(*pResult); // end guarded block - if (!rowCount) + if (!*pRowCount) { - PQclear(result); - return NULL; + PQclear(*pResult); + return false; } + return true; +} + +QueryResult* DatabasePostgre::Query(const char *sql) +{ + if (!mPGconn) + return 0; + + PGresult* result = NULL; + uint64 rowCount = 0; + uint32 fieldCount = 0; + + if(!_Query(sql,&result,&rowCount,&fieldCount)) + return NULL; QueryResultPostgre * queryResult = new QueryResultPostgre(result, rowCount, fieldCount); queryResult->NextRow(); @@ -165,6 +174,28 @@ QueryResult* DatabasePostgre::Query(const char *sql) return queryResult; } +QueryNamedResult* DatabasePostgre::QueryNamed(const char *sql) +{ + if (!mPGconn) + return 0; + + PGresult* result = NULL; + uint64 rowCount = 0; + uint32 fieldCount = 0; + + if(!_Query(sql,&result,&rowCount,&fieldCount)) + return NULL; + + QueryFieldNames names(fieldCount); + for (uint32 i = 0; i < fieldCount; i++) + names[i] = PQfname(result, i); + + QueryResultPostgre * queryResult = new QueryResultPostgre(result, rowCount, fieldCount); + queryResult->NextRow(); + + return new QueryNamedResult(queryResult,names); +} + bool DatabasePostgre::Execute(const char *sql) { diff --git a/src/shared/Database/DatabasePostgre.h b/src/shared/Database/DatabasePostgre.h index 40eb56a59..4d85eec98 100644 --- a/src/shared/Database/DatabasePostgre.h +++ b/src/shared/Database/DatabasePostgre.h @@ -44,6 +44,7 @@ class DatabasePostgre : public Database void InitDelayThread(); void HaltDelayThread(); QueryResult* Query(const char *sql); + QueryNamedResult* QueryNamed(const char *sql); bool Execute(const char *sql); bool DirectExecute(const char* sql); bool BeginTransaction(); @@ -68,5 +69,6 @@ class DatabasePostgre : public Database static size_t db_count; bool _TransactionCmd(const char *sql); + bool _Query(const char *sql, PGresult **pResult, uint64* pRowCount, uint32* pFieldCount); }; #endif diff --git a/src/shared/Database/QueryResult.h b/src/shared/Database/QueryResult.h index eba986d8a..16fd85d10 100644 --- a/src/shared/Database/QueryResult.h +++ b/src/shared/Database/QueryResult.h @@ -29,36 +29,52 @@ class MANGOS_DLL_SPEC QueryResult virtual bool NextRow() = 0; - typedef std::map FieldNames; - - uint32 GetField_idx(const std::string &name) const - { - for(FieldNames::const_iterator iter = GetFieldNames().begin(); iter != GetFieldNames().end(); ++iter) - { - if(iter->second == name) - return iter->first; - } - ASSERT(false && "unknown field name"); - return uint32(-1); - } - Field *Fetch() const { return mCurrentRow; } const Field & operator [] (int index) const { return mCurrentRow[index]; } - const Field & operator [] (const std::string &name) const - { - return mCurrentRow[GetField_idx(name)]; - } - uint32 GetFieldCount() const { return mFieldCount; } uint64 GetRowCount() const { return mRowCount; } - FieldNames const& GetFieldNames() const {return mFieldNames; } protected: Field *mCurrentRow; uint32 mFieldCount; uint64 mRowCount; - FieldNames mFieldNames; }; + +typedef std::vector QueryFieldNames; + +class MANGOS_DLL_SPEC QueryNamedResult +{ + public: + explicit QueryNamedResult(QueryResult* query, QueryFieldNames const& names) : mQuery(query), mFieldNames(names) {} + ~QueryNamedResult() { delete mQuery; } + + // compatible interface with QueryResult + bool NextRow() { return mQuery->NextRow(); } + Field *Fetch() const { return mQuery->Fetch(); } + uint32 GetFieldCount() const { return mQuery->GetFieldCount(); } + uint64 GetRowCount() const { return mQuery->GetRowCount(); } + Field const& operator[] (int index) const { return (*mQuery)[index]; } + + // named access + Field const& operator[] (const std::string &name) const { return mQuery->Fetch()[GetField_idx(name)]; } + QueryFieldNames const& GetFieldNames() const { return mFieldNames; } + + uint32 GetField_idx(const std::string &name) const + { + for(size_t idx = 0; idx < mFieldNames.size(); ++idx) + { + if(mFieldNames[idx] == name) + return idx; + } + ASSERT(false && "unknown field name"); + return uint32(-1); + } + + protected: + QueryResult *mQuery; + QueryFieldNames mFieldNames; +}; + #endif diff --git a/src/shared/Database/QueryResultMysql.cpp b/src/shared/Database/QueryResultMysql.cpp index 755a5532b..9eb2dde4e 100644 --- a/src/shared/Database/QueryResultMysql.cpp +++ b/src/shared/Database/QueryResultMysql.cpp @@ -20,20 +20,15 @@ #include "DatabaseEnv.h" -QueryResultMysql::QueryResultMysql(MYSQL_RES *result, uint64 rowCount, uint32 fieldCount) : -QueryResult(rowCount, fieldCount), mResult(result) +QueryResultMysql::QueryResultMysql(MYSQL_RES *result, MYSQL_FIELD *fields, uint64 rowCount, uint32 fieldCount) : + QueryResult(rowCount, fieldCount), mResult(result) { mCurrentRow = new Field[mFieldCount]; ASSERT(mCurrentRow); - MYSQL_FIELD *fields = mysql_fetch_fields(mResult); - for (uint32 i = 0; i < mFieldCount; i++) - { - mFieldNames[i] = fields[i].name; mCurrentRow[i].SetType(ConvertNativeType(fields[i].type)); - } } QueryResultMysql::~QueryResultMysql() diff --git a/src/shared/Database/QueryResultMysql.h b/src/shared/Database/QueryResultMysql.h index 2d00d09f4..e994719f8 100644 --- a/src/shared/Database/QueryResultMysql.h +++ b/src/shared/Database/QueryResultMysql.h @@ -32,7 +32,7 @@ class QueryResultMysql : public QueryResult { public: - QueryResultMysql(MYSQL_RES *result, uint64 rowCount, uint32 fieldCount); + QueryResultMysql(MYSQL_RES *result, MYSQL_FIELD *fields, uint64 rowCount, uint32 fieldCount); ~QueryResultMysql(); diff --git a/src/shared/Database/QueryResultPostgre.cpp b/src/shared/Database/QueryResultPostgre.cpp index aaae46c96..bd4bc72b8 100644 --- a/src/shared/Database/QueryResultPostgre.cpp +++ b/src/shared/Database/QueryResultPostgre.cpp @@ -21,17 +21,14 @@ #include "DatabaseEnv.h" QueryResultPostgre::QueryResultPostgre(PGresult *result, uint64 rowCount, uint32 fieldCount) : -QueryResult(rowCount, fieldCount), mResult(result), mTableIndex(0) + QueryResult(rowCount, fieldCount), mResult(result), mTableIndex(0) { mCurrentRow = new Field[mFieldCount]; ASSERT(mCurrentRow); for (uint32 i = 0; i < mFieldCount; i++) - { - mFieldNames[i] = PQfname(result, i); mCurrentRow[i].SetType(ConvertNativeType(PQftype( result, i ))); - } } QueryResultPostgre::~QueryResultPostgre() diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 6470b37e5..f9d2a281b 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 "7928" + #define REVISION_NR "7946" #endif // __REVISION_NR_H__