diff --git a/sql/mangos.sql b/sql/mangos.sql index 5e14b58164d..4d439b1f6c1 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_10263_03_mangos_pool_pool` bit(1) default NULL + `required_10270_01_mangos_reputation_spillover_template` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -14031,6 +14031,37 @@ LOCK TABLES `reputation_reward_rate` WRITE; /*!40000 ALTER TABLE `reputation_reward_rate` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Table structure for table `reputation_spillover_template` +-- + +DROP TABLE IF EXISTS `reputation_spillover_template`; +CREATE TABLE `reputation_spillover_template` ( + `faction` smallint(6) unsigned NOT NULL default '0' COMMENT 'faction entry', + `faction1` smallint(6) unsigned NOT NULL default '0' COMMENT 'faction to give spillover for', + `rate_1` float NOT NULL default '0' COMMENT 'the given rep points * rate', + `rank_1` tinyint(3) unsigned NOT NULL default '0' COMMENT 'max rank, above this will not give any spillover', + `faction2` smallint(6) unsigned NOT NULL default '0', + `rate_2` float NOT NULL default '0', + `rank_2` tinyint(3) unsigned NOT NULL default '0', + `faction3` smallint(6) unsigned NOT NULL default '0', + `rate_3` float NOT NULL default '0', + `rank_3` tinyint(3) unsigned NOT NULL default '0', + `faction4` smallint(6) unsigned NOT NULL default '0', + `rate_4` float NOT NULL default '0', + `rank_4` tinyint(3) unsigned NOT NULL default '0', + PRIMARY KEY (`faction`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Reputation spillover reputation gain'; + +-- +-- Dumping data for table `reputation_spillover_template` +-- + +LOCK TABLES `reputation_spillover_template` WRITE; +/*!40000 ALTER TABLE `reputation_spillover_template` DISABLE KEYS */; +/*!40000 ALTER TABLE `reputation_spillover_template` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `reserved_name` -- diff --git a/sql/updates/10270_01_mangos_reputation_spillover_template.sql b/sql/updates/10270_01_mangos_reputation_spillover_template.sql new file mode 100644 index 00000000000..b0c047f5a5b --- /dev/null +++ b/sql/updates/10270_01_mangos_reputation_spillover_template.sql @@ -0,0 +1,19 @@ +ALTER TABLE db_version CHANGE COLUMN required_10263_03_mangos_pool_pool required_10270_01_mangos_reputation_spillover_template bit; + +DROP TABLE IF EXISTS `reputation_spillover_template`; +CREATE TABLE `reputation_spillover_template` ( + `faction` smallint(6) unsigned NOT NULL default '0' COMMENT 'faction entry', + `faction1` smallint(6) unsigned NOT NULL default '0' COMMENT 'faction to give spillover for', + `rate_1` float NOT NULL default '0' COMMENT 'the given rep points * rate', + `rank_1` tinyint(3) unsigned NOT NULL default '0' COMMENT 'max rank, above this will not give any spillover', + `faction2` smallint(6) unsigned NOT NULL default '0', + `rate_2` float NOT NULL default '0', + `rank_2` tinyint(3) unsigned NOT NULL default '0', + `faction3` smallint(6) unsigned NOT NULL default '0', + `rate_3` float NOT NULL default '0', + `rank_3` tinyint(3) unsigned NOT NULL default '0', + `faction4` smallint(6) unsigned NOT NULL default '0', + `rate_4` float NOT NULL default '0', + `rank_4` tinyint(3) unsigned NOT NULL default '0', + PRIMARY KEY (`faction`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Reputation spillover reputation gain'; diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index d6c65b42c31..d013083c3bc 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -56,6 +56,7 @@ pkgdata_DATA = \ 10263_01_mangos_pool_creature.sql \ 10263_02_mangos_pool_gameobject.sql \ 10263_03_mangos_pool_pool.sql \ + 10270_01_mangos_reputation_spillover_template.sql \ README ## Additional files to include when running 'make dist' @@ -92,4 +93,5 @@ EXTRA_DIST = \ 10263_01_mangos_pool_creature.sql \ 10263_02_mangos_pool_gameobject.sql \ 10263_03_mangos_pool_pool.sql \ + 10270_01_mangos_reputation_spillover_template.sql \ README diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index ce3cdeadee4..cb3e47969c8 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -490,6 +490,7 @@ ChatCommand * ChatHandler::getCommandTable() { "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 }, + { "reputation_spillover_template",SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadReputationSpilloverTemplateCommand,"", 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 0f2968c50bb..455c1f607e5 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -406,6 +406,7 @@ class ChatHandler bool HandleReloadQuestTemplateCommand(const char* args); bool HandleReloadReservedNameCommand(const char*); bool HandleReloadReputationRewardRateCommand(const char* args); + bool HandleReloadReputationSpilloverTemplateCommand(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 18db39e8707..4097041ae1f 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -520,6 +520,14 @@ bool ChatHandler::HandleReloadReputationRewardRateCommand(const char*) return true; } +bool ChatHandler::HandleReloadReputationSpilloverTemplateCommand(const char*) +{ + sLog.outString( "Re-Loading `reputation_spillover_template` Table!" ); + sObjectMgr.LoadReputationSpilloverTemplate(); + SendGlobalSysMessage("DB table `reputation_spillover_template` 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 8ed1d31f21a..3f78070c1b5 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -6576,6 +6576,126 @@ void ObjectMgr::LoadReputationOnKill() sLog.outString(">> Loaded %u creature award reputation definitions", count); } +void ObjectMgr::LoadReputationSpilloverTemplate() +{ + m_RepSpilloverTemplateMap.clear(); // for reload case + + uint32 count = 0; + QueryResult *result = WorldDatabase.Query("SELECT faction, faction1, rate_1, rank_1, faction2, rate_2, rank_2, faction3, rate_3, rank_3, faction4, rate_4, rank_4 FROM reputation_spillover_template"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `reputation_spillover_template`, table is empty!"); + return; + } + + barGoLink bar((int)result->GetRowCount()); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + + uint32 factionId = fields[0].GetUInt32(); + + RepSpilloverTemplate repTemplate; + + repTemplate.faction[0] = fields[1].GetUInt32(); + repTemplate.faction_rate[0] = fields[2].GetFloat(); + repTemplate.faction_rank[0] = fields[3].GetUInt32(); + repTemplate.faction[1] = fields[4].GetUInt32(); + repTemplate.faction_rate[1] = fields[5].GetFloat(); + repTemplate.faction_rank[1] = fields[6].GetUInt32(); + repTemplate.faction[2] = fields[7].GetUInt32(); + repTemplate.faction_rate[2] = fields[8].GetFloat(); + repTemplate.faction_rank[2] = fields[9].GetUInt32(); + repTemplate.faction[3] = fields[10].GetUInt32(); + repTemplate.faction_rate[3] = fields[11].GetFloat(); + repTemplate.faction_rank[3] = fields[12].GetUInt32(); + + FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionId); + + if (!factionEntry) + { + sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", factionId); + continue; + } + + if (factionEntry->team == 0) + { + sLog.outErrorDb("Faction (faction.dbc) %u in `reputation_spillover_template` does not belong to any team, skipping", factionId); + continue; + } + + for (uint32 i = 0; i < MAX_SPILLOVER_FACTIONS; ++i) + { + if (repTemplate.faction[i]) + { + FactionEntry const *factionSpillover = sFactionStore.LookupEntry(repTemplate.faction[i]); + + if (!factionSpillover) + { + sLog.outErrorDb("Spillover faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template` for faction %u, skipping", repTemplate.faction[i], factionId); + continue; + } + + if (factionSpillover->reputationListID < 0) + { + sLog.outErrorDb("Spillover faction (faction.dbc) %u for faction %u in `reputation_spillover_template` can not be listed for client, and then useless, skipping", repTemplate.faction[i], factionId); + continue; + } + + if (repTemplate.faction_rank[i] >= MAX_REPUTATION_RANK) + { + sLog.outErrorDb("Rank %u used in `reputation_spillover_template` for spillover faction %u is not valid, skipping", repTemplate.faction_rank[i], repTemplate.faction[i]); + continue; + } + } + } + + FactionEntry const *factionEntry0 = sFactionStore.LookupEntry(repTemplate.faction[0]); + if (repTemplate.faction[0] && !factionEntry0) + { + sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[0]); + continue; + } + FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(repTemplate.faction[1]); + if (repTemplate.faction[1] && !factionEntry1) + { + sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[1]); + continue; + } + FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(repTemplate.faction[2]); + if (repTemplate.faction[2] && !factionEntry2) + { + sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[2]); + continue; + } + FactionEntry const *factionEntry3 = sFactionStore.LookupEntry(repTemplate.faction[3]); + if (repTemplate.faction[3] && !factionEntry3) + { + sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[3]); + continue; + } + + m_RepSpilloverTemplateMap[factionId] = repTemplate; + + ++count; + } + while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString(">> Loaded %u reputation_spillover_template", count); +} + void ObjectMgr::LoadPointsOfInterest() { mPointsOfInterest.clear(); // need for reload case diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index 5b6713f0460..d2fac42d6d8 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -258,6 +258,13 @@ struct ReputationOnKillEntry bool team_dependent; }; +struct RepSpilloverTemplate +{ + uint32 faction[MAX_SPILLOVER_FACTIONS]; + float faction_rate[MAX_SPILLOVER_FACTIONS]; + uint32 faction_rank[MAX_SPILLOVER_FACTIONS]; +}; + struct PointOfInterest { uint32 entry; @@ -472,6 +479,7 @@ class ObjectMgr typedef UNORDERED_MAP RepRewardRateMap; typedef UNORDERED_MAP RepOnKillMap; + typedef UNORDERED_MAP RepSpilloverTemplateMap; typedef UNORDERED_MAP PointOfInterestMap; @@ -619,6 +627,15 @@ class ObjectMgr return NULL; } + RepSpilloverTemplate const* GetRepSpilloverTemplate(uint32 factionId) const + { + RepSpilloverTemplateMap::const_iterator itr = m_RepSpilloverTemplateMap.find(factionId); + if (itr != m_RepSpilloverTemplateMap.end()) + return &itr->second; + + return NULL; + } + PointOfInterest const* GetPointOfInterest(uint32 id) const { PointOfInterestMap::const_iterator itr = mPointsOfInterest.find(id); @@ -708,6 +725,7 @@ class ObjectMgr void LoadReputationRewardRate(); void LoadReputationOnKill(); + void LoadReputationSpilloverTemplate(); void LoadPointsOfInterest(); void LoadQuestPOI(); @@ -1031,6 +1049,7 @@ class ObjectMgr RepRewardRateMap m_RepRewardRateMap; RepOnKillMap mRepOnKill; + RepSpilloverTemplateMap m_RepSpilloverTemplateMap; GossipMenusMap m_mGossipMenusMap; GossipMenuItemsMap m_mGossipMenuItemsMap; diff --git a/src/game/ReputationMgr.cpp b/src/game/ReputationMgr.cpp index d0d7c2fe982..08603d2bb01 100644 --- a/src/game/ReputationMgr.cpp +++ b/src/game/ReputationMgr.cpp @@ -133,14 +133,29 @@ void ReputationMgr::SendState(FactionState const* faction) const { if(faction->Flags & FACTION_FLAG_VISIBLE) //If faction is visible then update it { + uint32 count = 1; + WorldPacket data(SMSG_SET_FACTION_STANDING, (16)); // last check 2.4.0 data << (float) 0; // unk 2.4.0 data << (uint8) 0; // wotlk 8634 - data << (uint32) 1; // count - // for + + size_t p_count = data.wpos(); + data << (uint32) count; // placeholder + data << (uint32) faction->ReputationListID; data << (uint32) faction->Standing; - // end for + + for(FactionStateList::const_iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr) + { + if (itr->second.Changed && itr->second.ReputationListID != faction->ReputationListID) + { + data << (uint32) itr->second.ReputationListID; + data << (uint32) itr->second.Standing; + ++count; + } + } + + data.put(p_count, count); m_player->SendDirectMessage(&data); } } @@ -228,20 +243,57 @@ void ReputationMgr::Initialize() bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental) { - SimpleFactionsList const* flist = GetFactionTeamList(factionEntry->ID); - if (flist) + if (SimpleFactionsList const* flist = GetFactionTeamList(factionEntry->ID)) { bool res = false; for (SimpleFactionsList::const_iterator itr = flist->begin();itr != flist->end();++itr) { - FactionEntry const *factionEntryCalc = sFactionStore.LookupEntry(*itr); - if(factionEntryCalc) + if (FactionEntry const *factionEntryCalc = sFactionStore.LookupEntry(*itr)) + { res = SetOneFactionReputation(factionEntryCalc, standing, incremental); + + if (res) + { + FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID); + if (itr != m_factions.end()) + SendState(&itr->second); + } + } } return res; } else - return SetOneFactionReputation(factionEntry, standing, incremental); + { + // update for the actual faction first + bool res = SetOneFactionReputation(factionEntry, standing, incremental); + + if (res) + { + // then some spillover calculation here if it exist + if (const RepSpilloverTemplate *repTemplate = sObjectMgr.GetRepSpilloverTemplate(factionEntry->ID)) + { + for (uint32 i = 0; i < MAX_SPILLOVER_FACTIONS; ++i) + { + if (repTemplate->faction[i]) + { + if (m_player->GetReputationRank(repTemplate->faction[i]) <= ReputationRank(repTemplate->faction_rank[i])) + { + // bonuses are already given, so just modify standing by rate + int32 spilloverRep = standing * repTemplate->faction_rate[i]; + SetOneFactionReputation(sFactionStore.LookupEntry(repTemplate->faction[i]), spilloverRep, incremental); + } + } + } + } + + // now we can send it + FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID); + if (itr != m_factions.end()) + SendState(&itr->second); + } + + return res; + } } bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing, bool incremental) @@ -270,8 +322,6 @@ bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, in if(new_rank <= REP_HOSTILE) SetAtWar(&itr->second,true); - SendState(&itr->second); - UpdateRankCounters(old_rank, new_rank); m_player->ReputationChanged(factionEntry); diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 3d2857ae39b..609981a4293 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -112,6 +112,8 @@ enum ReputationRank #define MIN_REPUTATION_RANK (REP_HATED) #define MAX_REPUTATION_RANK 8 +#define MAX_SPILLOVER_FACTIONS 4 + enum MoneyConstants { COPPER = 1, diff --git a/src/game/World.cpp b/src/game/World.cpp index 405ba687595..2ff58a00034 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -1015,6 +1015,9 @@ void World::SetInitialWorldSettings() sLog.outString( "Loading Creature Reputation OnKill Data..." ); sObjectMgr.LoadReputationOnKill(); + sLog.outString( "Loading Reputation Spillover Data..." ); + sObjectMgr.LoadReputationSpilloverTemplate(); + sLog.outString( "Loading Points Of Interest Data..." ); sObjectMgr.LoadPointsOfInterest(); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 87083c01d6b..f8e52eac408 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 "10269" + #define REVISION_NR "10270" #endif // __REVISION_NR_H__ diff --git a/src/shared/revision_sql.h b/src/shared/revision_sql.h index 2d0228be2dc..e276ddc79e4 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_10254_01_characters_auctionhouse" - #define REVISION_DB_MANGOS "required_10263_03_mangos_pool_pool" + #define REVISION_DB_MANGOS "required_10270_01_mangos_reputation_spillover_template" #define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version" #endif // __REVISION_SQL_H__