diff --git a/sql/mangos.sql b/sql/mangos.sql index 1fdb3b9e2..b9ba48128 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -24,7 +24,7 @@ CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, `cache_id` int(10) default '0', - `required_10251_01_mangos_command` bit(1) default NULL + `required_10252_01_mangos_reputation_reward_rate` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -14004,6 +14004,28 @@ LOCK TABLES `reference_loot_template` WRITE; /*!40000 ALTER TABLE `reference_loot_template` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Table structure for table `reputation_reward_rate` +-- + +DROP TABLE IF EXISTS `reputation_reward_rate`; +CREATE TABLE `reputation_reward_rate` ( + `faction` mediumint(8) unsigned NOT NULL default '0', + `quest_rate` float NOT NULL default '1', + `creature_rate` float NOT NULL default '1', + `spell_rate` float NOT NULL default '1', + PRIMARY KEY (`faction`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `reputation_reward_rate` +-- + +LOCK TABLES `reputation_reward_rate` WRITE; +/*!40000 ALTER TABLE `reputation_reward_rate` DISABLE KEYS */; +/*!40000 ALTER TABLE `reputation_reward_rate` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `reserved_name` -- diff --git a/sql/updates/10252_01_mangos_reputation_reward_rate.sql b/sql/updates/10252_01_mangos_reputation_reward_rate.sql new file mode 100644 index 000000000..b337458ed --- /dev/null +++ b/sql/updates/10252_01_mangos_reputation_reward_rate.sql @@ -0,0 +1,10 @@ +ALTER TABLE db_version CHANGE COLUMN required_10251_01_mangos_command required_10252_01_mangos_reputation_reward_rate bit; + +DROP TABLE IF EXISTS `reputation_reward_rate`; +CREATE TABLE `reputation_reward_rate` ( + `faction` mediumint(8) unsigned NOT NULL default '0', + `quest_rate` float NOT NULL default '1', + `creature_rate` float NOT NULL default '1', + `spell_rate` float NOT NULL default '1', + PRIMARY KEY (`faction`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index 2fef3e905..647301cc9 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -121,6 +121,7 @@ pkgdata_DATA = \ 10237_01_mangos_spell_bonus_data.sql \ 10244_01_mangos_command.sql \ 10251_01_mangos_command.sql \ + 10252_01_mangos_reputation_reward_rate.sql \ README ## Additional files to include when running 'make dist' @@ -222,4 +223,5 @@ EXTRA_DIST = \ 10237_01_mangos_spell_bonus_data.sql \ 10244_01_mangos_command.sql \ 10251_01_mangos_command.sql \ + 10252_01_mangos_reputation_reward_rate.sql \ README diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 99e7c7e50..6a168cf1d 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -480,6 +480,7 @@ ChatCommand * ChatHandler::getCommandTable() { "quest_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestTemplateCommand, "", NULL }, { "reference_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesReferenceCommand, "", NULL }, { "reserved_name", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadReservedNameCommand, "", NULL }, + { "reputation_reward_rate", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadReputationRewardRateCommand, "", NULL }, { "skill_discovery_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillDiscoveryTemplateCommand, "", NULL }, { "skill_extra_item_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillExtraItemTemplateCommand, "", NULL }, { "skill_fishing_base_level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillFishingBaseLevelCommand, "", NULL }, diff --git a/src/game/Chat.h b/src/game/Chat.h index f18440aaa..9a0971052 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -400,6 +400,7 @@ class ChatHandler bool HandleReloadQuestStartScriptsCommand(const char* args); bool HandleReloadQuestTemplateCommand(const char* args); bool HandleReloadReservedNameCommand(const char*); + bool HandleReloadReputationRewardRateCommand(const char* args); bool HandleReloadSkillDiscoveryTemplateCommand(const char* args); bool HandleReloadSkillExtraItemTemplateCommand(const char* args); bool HandleReloadSkillFishingBaseLevelCommand(const char* args); diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index b52ce0724..0eed06721 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -512,6 +512,14 @@ bool ChatHandler::HandleReloadReservedNameCommand(const char*) return true; } +bool ChatHandler::HandleReloadReputationRewardRateCommand(const char*) +{ + sLog.outString( "Re-Loading `reputation_reward_rate` Table!" ); + sObjectMgr.LoadReputationRewardRate(); + SendGlobalSysMessage("DB table `reputation_reward_rate` reloaded."); + return true; +} + bool ChatHandler::HandleReloadSkillDiscoveryTemplateCommand(const char* /*args*/) { sLog.outString( "Re-Loading Skill Discovery Table..." ); diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 5746f7d86..7de27ec53 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -6427,6 +6427,77 @@ void ObjectMgr::LoadCorpses() sLog.outString( ">> Loaded %u corpses", count ); } +void ObjectMgr::LoadReputationRewardRate() +{ + m_RepRewardRateMap.clear(); // for reload case + + uint32 count = 0; + QueryResult *result = WorldDatabase.Query("SELECT faction, quest_rate, creature_rate, spell_rate FROM reputation_reward_rate"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `reputation_reward_rate`, table is empty!"); + return; + } + + barGoLink bar((int)result->GetRowCount()); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + + uint32 factionId = fields[0].GetUInt32(); + + RepRewardRate repRate; + + repRate.quest_rate = fields[1].GetFloat(); + repRate.creature_rate = fields[2].GetFloat(); + repRate.spell_rate = fields[3].GetFloat(); + + FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionId); + if (!factionEntry) + { + sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `reputation_reward_rate`", factionId); + continue; + } + + if (repRate.quest_rate < 0.0f) + { + sLog.outErrorDb("Table reputation_reward_rate has quest_rate with invalid rate %f, skipping data for faction %u", repRate.quest_rate, factionId); + continue; + } + + if (repRate.creature_rate < 0.0f) + { + sLog.outErrorDb("Table reputation_reward_rate has creature_rate with invalid rate %f, skipping data for faction %u", repRate.creature_rate, factionId); + continue; + } + + if (repRate.spell_rate < 0.0f) + { + sLog.outErrorDb("Table reputation_reward_rate has spell_rate with invalid rate %f, skipping data for faction %u", repRate.spell_rate, factionId); + continue; + } + + m_RepRewardRateMap[factionId] = repRate; + + ++count; + } + while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString(">> Loaded %u reputation_reward_rate", count); +} + void ObjectMgr::LoadReputationOnKill() { uint32 count = 0; diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index 9afc138da..a3ccb2856 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -237,6 +237,14 @@ struct MailLevelReward typedef std::list MailLevelRewardList; typedef UNORDERED_MAP MailLevelRewardMap; +// We assume the rate is in general the same for all three types below, but chose to keep three for scalability and customization +struct RepRewardRate +{ + float quest_rate; // We allow rate = 0.0 in database. For this case, it means that + float creature_rate; // no reputation are given at all for this faction/rate type. + float spell_rate; // not implemented yet (SPELL_EFFECT_REPUTATION) +}; + struct ReputationOnKillEntry { uint32 repfaction1; @@ -460,7 +468,9 @@ class ObjectMgr typedef UNORDERED_MAP AreaTriggerScriptMap; + typedef UNORDERED_MAP RepRewardRateMap; typedef UNORDERED_MAP RepOnKillMap; + typedef UNORDERED_MAP PointOfInterestMap; typedef UNORDERED_MAP WeatherZoneMap; @@ -590,6 +600,15 @@ class ObjectMgr uint32 GetAreaTriggerScriptId(uint32 trigger_id); + RepRewardRate const* GetRepRewardRate(uint32 factionId) const + { + RepRewardRateMap::const_iterator itr = m_RepRewardRateMap.find(factionId); + if (itr != m_RepRewardRateMap.end()) + return &itr->second; + + return NULL; + } + ReputationOnKillEntry const* GetReputationOnKilEntry(uint32 id) const { RepOnKillMap::const_iterator itr = mRepOnKill.find(id); @@ -685,7 +704,9 @@ class ObjectMgr void LoadCorpses(); void LoadFishingBaseSkillLevel(); + void LoadReputationRewardRate(); void LoadReputationOnKill(); + void LoadPointsOfInterest(); void LoadQuestPOI(); @@ -1006,6 +1027,7 @@ class ObjectMgr AreaTriggerMap mAreaTriggers; AreaTriggerScriptMap mAreaTriggerScripts; + RepRewardRateMap m_RepRewardRateMap; RepOnKillMap mRepOnKill; GossipMenusMap m_mGossipMenusMap; diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 5878d44ab..6f349275d 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -6236,16 +6236,27 @@ ReputationRank Player::GetReputationRank(uint32 faction) const } //Calculate total reputation percent player gain with quest/creature level -int32 Player::CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest) +int32 Player::CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest, bool noQuestBonus) { float percent = 100.0f; + // Get the generic rate first + if (const RepRewardRate *repData = sObjectMgr.GetRepRewardRate(faction)) + { + float repRate = for_quest ? repData->quest_rate : repData->creature_rate; + percent *= repRate; + + // for custom, a rate of 0.0 will totally disable reputation gain for this faction/type + if (repRate <= 0.0f) + percent = repRate; + } + float rate = for_quest ? sWorld.getConfig(CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_QUEST) : sWorld.getConfig(CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_KILL); if (rate != 1.0f && creatureOrQuestLevel <= MaNGOS::XP::GetGrayLevel(getLevel())) percent *= rate; - float repMod = (float)GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN); + float repMod = noQuestBonus ? 0.0f : (float)GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN); if (!for_quest) repMod += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_FACTION_REPUTATION_GAIN, faction); @@ -6316,11 +6327,10 @@ void Player::RewardReputation(Quest const *pQuest) if (!pQuest->RewRepFaction[i]) continue; - // For future, this row should be used as "override". Example quests are 10298 and 10870. - // Typically, no diplomacy mod must apply to the final value (flat). Note the formula must be (finalValue = DBvalue/100) + // No diplomacy mod are applied to the final value (flat). Note the formula (finalValue = DBvalue/100) if (pQuest->RewRepValue[i]) { - int32 rep = CalculateReputationGain(GetQuestLevelForPlayer(pQuest), pQuest->RewRepValue[i], pQuest->RewRepFaction[i], true); + int32 rep = CalculateReputationGain(GetQuestLevelForPlayer(pQuest), pQuest->RewRepValue[i]/100, pQuest->RewRepFaction[i], true, true); if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i])) GetReputationMgr().ModifyReputation(factionEntry, rep); diff --git a/src/game/Player.h b/src/game/Player.h index 57d2e7614..46daa5e3c 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -2600,7 +2600,7 @@ class MANGOS_DLL_SPEC Player : public Unit Item* _StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, bool update ); void UpdateKnownCurrencies(uint32 itemId, bool apply); - int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest); + int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest, bool noQuestBonus = false); void AdjustQuestReqItemCount( Quest const* pQuest, QuestStatusData& questStatusData ); void SetCanDelayTeleport(bool setting) { m_bCanDelayTeleport = setting; } diff --git a/src/game/World.cpp b/src/game/World.cpp index f20db5d85..405ba6875 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -1009,6 +1009,9 @@ void World::SetInitialWorldSettings() sLog.outString( "Loading ItemRequiredTarget..."); sObjectMgr.LoadItemRequiredTarget(); + sLog.outString( "Loading Reputation Reward Rates..."); + sObjectMgr.LoadReputationRewardRate(); + sLog.outString( "Loading Creature Reputation OnKill Data..." ); sObjectMgr.LoadReputationOnKill(); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index f761398ad..ab1048e0e 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 "10251" + #define REVISION_NR "10252" #endif // __REVISION_NR_H__ diff --git a/src/shared/revision_sql.h b/src/shared/revision_sql.h index 61c3ca1a1..10ac0d37f 100644 --- a/src/shared/revision_sql.h +++ b/src/shared/revision_sql.h @@ -1,6 +1,6 @@ #ifndef __REVISION_SQL_H__ #define __REVISION_SQL_H__ #define REVISION_DB_CHARACTERS "required_10160_02_characters_pet_aura" - #define REVISION_DB_MANGOS "required_10251_01_mangos_command" + #define REVISION_DB_MANGOS "required_10252_01_mangos_reputation_reward_rate" #define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version" #endif // __REVISION_SQL_H__