TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
SkillDiscovery.cpp File Reference
#include "DatabaseEnv.h"
#include "Log.h"
#include "World.h"
#include "Util.h"
#include "SkillDiscovery.h"
#include "SpellMgr.h"
#include "Player.h"
#include "SpellInfo.h"
#include <map>
+ Include dependency graph for SkillDiscovery.cpp:

Classes

struct  SkillDiscoveryEntry
 

Typedefs

typedef std::list
< SkillDiscoveryEntry
SkillDiscoveryList
 
typedef std::unordered_map
< int32, SkillDiscoveryList
SkillDiscoveryMap
 

Functions

void LoadSkillDiscoveryTable ()
 
uint32 GetExplicitDiscoverySpell (uint32 spellId, Player *player)
 
bool HasDiscoveredAllSpells (uint32 spellId, Player *player)
 
uint32 GetSkillDiscoverySpell (uint32 skillId, uint32 spellId, Player *player)
 

Variables

static SkillDiscoveryMap SkillDiscoveryStore
 

Typedef Documentation

typedef std::unordered_map<int32, SkillDiscoveryList> SkillDiscoveryMap

Function Documentation

uint32 GetExplicitDiscoverySpell ( uint32  spellId,
Player *  player 
)
159 {
160  // explicit discovery spell chances (always success if case exist)
161  // in this case we have both skill and spell
162  SkillDiscoveryMap::const_iterator tab = SkillDiscoveryStore.find(int32(spellId));
163  if (tab == SkillDiscoveryStore.end())
164  return 0;
165 
166  SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
167  uint32 skillvalue = bounds.first != bounds.second ? player->GetSkillValue(bounds.first->second->SkillLine) : uint32(0);
168 
169  float full_chance = 0;
170  for (SkillDiscoveryList::const_iterator item_iter = tab->second.begin(); item_iter != tab->second.end(); ++item_iter)
171  if (item_iter->reqSkillValue <= skillvalue)
172  if (!player->HasSpell(item_iter->spellId))
173  full_chance += item_iter->chance;
174 
175  float rate = full_chance / 100.0f;
176  float roll = (float)rand_chance() * rate; // roll now in range 0..full_chance
177 
178  for (SkillDiscoveryList::const_iterator item_iter = tab->second.begin(); item_iter != tab->second.end(); ++item_iter)
179  {
180  if (item_iter->reqSkillValue > skillvalue)
181  continue;
182 
183  if (player->HasSpell(item_iter->spellId))
184  continue;
185 
186  if (item_iter->chance > roll)
187  return item_iter->spellId;
188 
189  roll -= item_iter->chance;
190  }
191 
192  return 0;
193 }
static SkillDiscoveryMap SkillDiscoveryStore
Definition: SkillDiscovery.cpp:45
double rand_chance()
Definition: Random.cpp:74
std::pair< SkillLineAbilityMap::const_iterator, SkillLineAbilityMap::const_iterator > SkillLineAbilityMapBounds
Definition: SpellMgr.h:549
#define sSpellMgr
Definition: SpellMgr.h:756
uint32_t uint32
Definition: Define.h:150
int32_t int32
Definition: g3dmath.h:167
uint32_t uint32
Definition: g3dmath.h:168

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

uint32 GetSkillDiscoverySpell ( uint32  skillId,
uint32  spellId,
Player *  player 
)
209 {
210  uint32 skillvalue = skillId ? player->GetSkillValue(skillId) : uint32(0);
211 
212  // check spell case
213  SkillDiscoveryMap::const_iterator tab = SkillDiscoveryStore.find(int32(spellId));
214 
215  if (tab != SkillDiscoveryStore.end())
216  {
217  for (SkillDiscoveryList::const_iterator item_iter = tab->second.begin(); item_iter != tab->second.end(); ++item_iter)
218  {
219  if (roll_chance_f(item_iter->chance * sWorld->getRate(RATE_SKILL_DISCOVERY)) &&
220  item_iter->reqSkillValue <= skillvalue &&
221  !player->HasSpell(item_iter->spellId))
222  return item_iter->spellId;
223  }
224 
225  return 0;
226  }
227 
228  if (!skillId)
229  return 0;
230 
231  // check skill line case
232  tab = SkillDiscoveryStore.find(-(int32)skillId);
233  if (tab != SkillDiscoveryStore.end())
234  {
235  for (SkillDiscoveryList::const_iterator item_iter = tab->second.begin(); item_iter != tab->second.end(); ++item_iter)
236  {
237  if (roll_chance_f(item_iter->chance * sWorld->getRate(RATE_SKILL_DISCOVERY)) &&
238  item_iter->reqSkillValue <= skillvalue &&
239  !player->HasSpell(item_iter->spellId))
240  return item_iter->spellId;
241  }
242 
243  return 0;
244  }
245 
246  return 0;
247 }
static SkillDiscoveryMap SkillDiscoveryStore
Definition: SkillDiscovery.cpp:45
#define sWorld
Definition: World.h:887
bool roll_chance_f(float chance)
Definition: Random.h:47
int32_t int32
Definition: Define.h:146
uint32_t uint32
Definition: Define.h:150
int32_t int32
Definition: g3dmath.h:167
Definition: World.h:391
uint32_t uint32
Definition: g3dmath.h:168

+ Here is the call graph for this function:

bool HasDiscoveredAllSpells ( uint32  spellId,
Player *  player 
)
196 {
197  SkillDiscoveryMap::const_iterator tab = SkillDiscoveryStore.find(int32(spellId));
198  if (tab == SkillDiscoveryStore.end())
199  return true;
200 
201  for (SkillDiscoveryList::const_iterator item_iter = tab->second.begin(); item_iter != tab->second.end(); ++item_iter)
202  if (!player->HasSpell(item_iter->spellId))
203  return false;
204 
205  return true;
206 }
static SkillDiscoveryMap SkillDiscoveryStore
Definition: SkillDiscovery.cpp:45
int32_t int32
Definition: g3dmath.h:167

+ Here is the caller graph for this function:

void LoadSkillDiscoveryTable ( )
48 {
49  uint32 oldMSTime = getMSTime();
50 
51  SkillDiscoveryStore.clear(); // need for reload
52 
53  // 0 1 2 3
54  QueryResult result = WorldDatabase.Query("SELECT spellId, reqSpell, reqSkillValue, chance FROM skill_discovery_template");
55 
56  if (!result)
57  {
58  TC_LOG_ERROR("server.loading", ">> Loaded 0 skill discovery definitions. DB table `skill_discovery_template` is empty.");
59  return;
60  }
61 
62  uint32 count = 0;
63 
64  std::ostringstream ssNonDiscoverableEntries;
65  std::set<uint32> reportedReqSpells;
66 
67  do
68  {
69  Field* fields = result->Fetch();
70 
71  uint32 spellId = fields[0].GetUInt32();
72  int32 reqSkillOrSpell = fields[1].GetInt32();
73  uint32 reqSkillValue = fields[2].GetUInt16();
74  float chance = fields[3].GetFloat();
75 
76  if (chance <= 0) // chance
77  {
78  ssNonDiscoverableEntries << "spellId = " << spellId << " reqSkillOrSpell = " << reqSkillOrSpell
79  << " reqSkillValue = " << reqSkillValue << " chance = " << chance << "(chance problem)\n";
80  continue;
81  }
82 
83  if (reqSkillOrSpell > 0) // spell case
84  {
85  uint32 absReqSkillOrSpell = uint32(reqSkillOrSpell);
86  SpellInfo const* reqSpellInfo = sSpellMgr->GetSpellInfo(absReqSkillOrSpell);
87  if (!reqSpellInfo)
88  {
89  if (reportedReqSpells.find(absReqSkillOrSpell) == reportedReqSpells.end())
90  {
91  TC_LOG_ERROR("sql.sql", "Spell (ID: %u) have not existed spell (ID: %i) in `reqSpell` field in `skill_discovery_template` table", spellId, reqSkillOrSpell);
92  reportedReqSpells.insert(absReqSkillOrSpell);
93  }
94  continue;
95  }
96 
97  // mechanic discovery
98  if (reqSpellInfo->Mechanic != MECHANIC_DISCOVERY &&
99  // explicit discovery ability
100  !reqSpellInfo->IsExplicitDiscovery())
101  {
102  if (reportedReqSpells.find(absReqSkillOrSpell) == reportedReqSpells.end())
103  {
104  TC_LOG_ERROR("sql.sql", "Spell (ID: %u) not have MECHANIC_DISCOVERY (28) value in Mechanic field in spell.dbc"
105  " and not 100%% chance random discovery ability but listed for spellId %u (and maybe more) in `skill_discovery_template` table",
106  absReqSkillOrSpell, spellId);
107  reportedReqSpells.insert(absReqSkillOrSpell);
108  }
109  continue;
110  }
111 
112  SkillDiscoveryStore[reqSkillOrSpell].push_back(SkillDiscoveryEntry(spellId, reqSkillValue, chance));
113  }
114  else if (reqSkillOrSpell == 0) // skill case
115  {
116  SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
117 
118  if (bounds.first == bounds.second)
119  {
120  TC_LOG_ERROR("sql.sql", "Spell (ID: %u) not listed in `SkillLineAbility.dbc` but listed with `reqSpell`=0 in `skill_discovery_template` table", spellId);
121  continue;
122  }
123 
124  for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
125  SkillDiscoveryStore[-int32(_spell_idx->second->SkillLine)].push_back(SkillDiscoveryEntry(spellId, reqSkillValue, chance));
126  }
127  else
128  {
129  TC_LOG_ERROR("sql.sql", "Spell (ID: %u) have negative value in `reqSpell` field in `skill_discovery_template` table", spellId);
130  continue;
131  }
132 
133  ++count;
134  }
135  while (result->NextRow());
136 
137  if (!ssNonDiscoverableEntries.str().empty())
138  TC_LOG_ERROR("sql.sql", "Some items can't be successfully discovered: have in chance field value < 0.000001 in `skill_discovery_template` DB table . List:\n%s", ssNonDiscoverableEntries.str().c_str());
139 
140  // report about empty data for explicit discovery spells
141  for (uint32 spell_id = 1; spell_id < sSpellMgr->GetSpellInfoStoreSize(); ++spell_id)
142  {
143  SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(spell_id);
144  if (!spellEntry)
145  continue;
146 
147  // skip not explicit discovery spells
148  if (!spellEntry->IsExplicitDiscovery())
149  continue;
150 
151  if (SkillDiscoveryStore.find(int32(spell_id)) == SkillDiscoveryStore.end())
152  TC_LOG_ERROR("sql.sql", "Spell (ID: %u) is 100%% chance random discovery ability but not have data in `skill_discovery_template` table", spell_id);
153  }
154 
155  TC_LOG_INFO("server.loading", ">> Loaded %u skill discovery definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
156 }
static SkillDiscoveryMap SkillDiscoveryStore
Definition: SkillDiscovery.cpp:45
float GetFloat() const
Definition: Field.h:222
Definition: SpellInfo.h:326
Class used to access individual fields of database query result.
Definition: Field.h:56
uint32 getMSTime()
Definition: Timer.h:24
WorldDatabaseWorkerPool WorldDatabase
Accessor to the world database.
Definition: DatabaseEnv.cpp:20
uint32 Mechanic
Definition: SpellInfo.h:332
std::pair< SkillLineAbilityMap::const_iterator, SkillLineAbilityMap::const_iterator > SkillLineAbilityMapBounds
Definition: SpellMgr.h:549
Definition: SkillDiscovery.cpp:29
#define sSpellMgr
Definition: SpellMgr.h:756
int32_t int32
Definition: Define.h:146
uint32_t uint32
Definition: Define.h:150
std::shared_ptr< ResultSet > QueryResult
Definition: QueryResult.h:61
Definition: SharedDefines.h:1818
uint16 GetUInt16() const
Definition: Field.h:108
bool IsExplicitDiscovery() const
Definition: SpellInfo.cpp:1228
int32 GetInt32() const
Definition: Field.h:165
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition: Timer.h:42
QueryResult Query(const char *sql, T *connection=nullptr)
Definition: DatabaseWorkerPool.cpp:113
uint32 GetUInt32() const
Definition: Field.h:146
int32_t int32
Definition: g3dmath.h:167
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:201
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:207
uint32_t uint32
Definition: g3dmath.h:168

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Variable Documentation

SkillDiscoveryMap SkillDiscoveryStore
static